Skip to content

Commit

Permalink
FI-1136 fix: use E2ED_DOCKER_IMAGE instead of dockerImage pack op…
Browse files Browse the repository at this point in the history
…tion

feat: support dotenv file `./autotests/.env`
fix: use `E2ED_PATH_TO_TS_CONFIG_OF_PROJECT_FROM_ROOT` environment variables
  • Loading branch information
uid11 committed Jan 23, 2024
1 parent e679992 commit 41bb7c7
Show file tree
Hide file tree
Showing 22 changed files with 258 additions and 96 deletions.
8 changes: 5 additions & 3 deletions .prettierrc.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
trailingComma: all
arrowParens: always
singleQuote: true
bracketSpacing: false
jsxSingleQuote: false
overrides:
- {files: ./tsconfig.json, options: {parser: json}}
printWidth: 100
bracketSpacing: false
singleQuote: true
trailingComma: all
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,6 @@ The functions accept a start info object, and can return new full pack config,
which in this case will be included in the start info object, and will be used for running pack.
Each function can thus access the results of the previous function.

`dockerImage: string`: the name of the docker image where the tests will run.
The image must be based on the e2ed base image.

`enableChromeDevToolsProtocol: boolean`: enables [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/)
for browser control in tests (instead of `testcafe-hammerhead`).

Expand Down Expand Up @@ -405,6 +402,17 @@ If the wait is longer than this timeout, then the promise returned by the `waitF

### Environment variables

Required environment variables are defined in the `./autotests/.env` file (they cannot be deleted):

`E2ED_DOCKER_IMAGE`: the name of the docker image where the tests will run.
The image must be based on the e2ed base image.

`E2ED_PATH_TO_TS_CONFIG_OF_PROJECT_FROM_ROOT`: the path to TypeScript config file of the project
from the root directory of the project. The project should have one common TypeScript config
for both the application code and the autotest code.

You can pass the following optional environment variables to the `e2ed` process in any standard way:

`E2ED_ORIGIN`: origin-part of the url (`protocol` + `host`) on which the tests will be run. For example, `https://google.com`.

`E2ED_DEBUG`: run e2ed in `nodejs` debug mode (`--inspect-brk=0.0.0.0`) if this variable is not empty.
Expand Down
10 changes: 10 additions & 0 deletions autotests/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# This required file in standard dotenv format defines the environment variables
# with which all packs will be run.
# {@link https://www.npmjs.com/package/dotenv}

# Required variable: the name of the docker image where the tests will run.
E2ED_DOCKER_IMAGE='e2edhub/e2ed'

# Required variable: the path to TypeScript config file of the project
# from the root directory of the project.
E2ED_PATH_TO_TS_CONFIG_OF_PROJECT_FROM_ROOT='./tsconfig.json'
17 changes: 9 additions & 8 deletions autotests/bin/runDocker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ set +u
CONTAINER_LABEL="e2ed"
DEBUG_PORT="${E2ED_DOCKER_DEBUG_PORT:-9229}"
DIR="${E2ED_WORKDIR:-$PWD}"
DOCKER_IMAGE=$(grep -m1 dockerImage $DIR/$1 | sed -e "s/^[^'\"\`]*['\"\`]//" -e "s/['\"\`][^'\"\`]*$//")
MOUNTDIR="${E2ED_MOUNTDIR:-$DIR}"
WITH_DEBUG=$([[ -z $E2ED_DEBUG ]] && echo "" || echo "--env E2ED_DEBUG=$DEBUG_PORT --publish $DEBUG_PORT:$DEBUG_PORT --publish $((DEBUG_PORT + 1)):$((DEBUG_PORT + 1))")
VERSION=$(grep -m1 \"e2ed\": $DIR/package.json | cut -d '"' -f 4)

if [[ -z $DOCKER_IMAGE ]]
source ./autotests/.env

if [[ -z $E2ED_DOCKER_IMAGE ]]
then
echo "Error: The pack config does not contain an explicit line with \"dockerImage\"."
echo "Add it so that the bash script can read the docker image."
echo "Error: The \"autotests/.env\" file does not contain E2ED_DOCKER_IMAGE variable."
echo "Add it so that \"runDocker.sh\" script can run the docker image."
echo "Exit with code 9"
exit 9
fi
Expand All @@ -23,16 +24,16 @@ onExit() {

if [[ -z $CONTAINER_ID ]]
then
echo "Docker container from image $DOCKER_IMAGE:$VERSION already stopped"
echo "Docker container from image $E2ED_DOCKER_IMAGE:$VERSION already stopped"
else
echo "Stop docker container from image $DOCKER_IMAGE:$VERSION"
echo "Stop docker container from image $E2ED_DOCKER_IMAGE:$VERSION"
docker stop --time=60 $CONTAINER_ID
fi

exit
}

echo "Run docker image $DOCKER_IMAGE:$VERSION"
echo "Run docker image $E2ED_DOCKER_IMAGE:$VERSION"

trap "onExit" EXIT

Expand All @@ -45,7 +46,7 @@ docker run \
--volume $MOUNTDIR:$MOUNTDIR \
--workdir $DIR \
$WITH_DEBUG \
$DOCKER_IMAGE:$VERSION \
$E2ED_DOCKER_IMAGE:$VERSION \
& PID=$!

wait $PID
2 changes: 0 additions & 2 deletions autotests/packs/allTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ export const pack: Pack = {
customPackProperties: {internalPackRunId: 0, name: 'allTests'},
doAfterPack,
doBeforePack,
dockerImage: 'e2edhub/e2ed',
enableChromeDevToolsProtocol: true,
enableHeadlessMode: true,
enableLiveMode: false,
Expand All @@ -68,7 +67,6 @@ export const pack: Pack = {
pageRequestTimeout: 30_000,
pageStabilizationInterval: 500,
pathToScreenshotsDirectoryForReport: './screenshots',
pathToTsConfigOfProjectFromRoot: './tsconfig.json',
port1: 1337,
port2: 1338,
reportFileName: 'report.html',
Expand Down
1 change: 0 additions & 1 deletion autotests/packs/local.example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ import type {Pack} from 'autotests/types/pack';
export const pack: Pack = {
...allTestsPack,
browserInitTimeout: 40_000,
dockerImage: 'e2edhub/e2ed',
};
46 changes: 26 additions & 20 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,29 @@ Modules in the dependency graph should only import the modules above them:
12. `utils/valueToString`
13. `utils/error`
14. `utils/asserts`
15. `utils/userland`
16. `utils/fn`
17. `utils/environment`
18. `testcaferc`
19. `utils/config`
20. `utils/runLabel`
21. `utils/generalLog`
22. `utils/fs`
23. `selectors`
24. `Route`
25. `ApiRoute`
26. `PageRoute`
27. `testController`
28. `useContext`
29. `context`
30. `utils/log`
31. `utils/waitForEvents`
32. `utils/expect`
33. `expect`
34. ...
15. `utils/clone`
16. `utils/notIncludedInPackTests`
17. `utils/userland`
18. `utils/fn`
19. `utils/environment`
20. `utils/packCompiler`
21. `testcaferc`
22. `utils/config`
23. `utils/runLabel`
24. `utils/generalLog`
25. `utils/fs`
26. `utils/tests`
27. `utils/end`
28. `utils/pack`
29. `selectors`
30. `Route`
31. `ApiRoute`
32. `PageRoute`
33. `testController`
34. `useContext`
35. `context`
36. `utils/log`
37. `utils/waitForEvents`
38. `utils/expect`
39. `expect`
40. ...
1 change: 1 addition & 0 deletions src/constants/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export {
ABSOLUTE_PATH_TO_PROJECT_ROOT_DIRECTORY,
AUTOTESTS_DIRECTORY_PATH,
COMPILED_USERLAND_CONFIG_DIRECTORY,
DOT_ENV_PATH,
EVENTS_DIRECTORY_PATH,
INSTALLED_E2ED_DIRECTORY_PATH,
REPORTS_DIRECTORY_PATH,
Expand Down
8 changes: 7 additions & 1 deletion src/constants/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ export const INSTALLED_E2ED_DIRECTORY_PATH = relative(
*/
export const AUTOTESTS_DIRECTORY_PATH = 'autotests' as DirectoryPathFromRoot;

/**
* Relative (from root) path to `.env` file in directory with autotests.
* @internal
*/
export const DOT_ENV_PATH = join(AUTOTESTS_DIRECTORY_PATH, '.env') as FilePathFromRoot;

/**
* Relative (from root) path to reports directory.
* @internal
Expand Down Expand Up @@ -82,7 +88,7 @@ export const SCREENSHOTS_DIRECTORY_PATH = join(
export const START_INFO_PATH = join(TMP_DIRECTORY_PATH, 'startInfo.json') as FilePathFromRoot;

/**
* Relative (from root) path to testcaferc file,
* Relative (from root) path to `testcaferc` file,
* that plays the role of the internal TestCafe config.
* @internal
*/
Expand Down
13 changes: 0 additions & 13 deletions src/types/config/ownE2edConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,6 @@ export type OwnE2edConfig<
liteReport: LiteReport<CustomPackProperties, CustomReportProperties, SkipTests, TestMeta>,
) => MaybePromise<CustomReportProperties | Void>)[];

/**
* The name of the docker image where the tests will run.
* The image must be based on the e2ed base image.
*/
dockerImage: string;

/**
* Enables Chrome DevTools Protocol for browser control in tests (instead of `testcafe-hammerhead`).
* {@link https://chromedevtools.github.io/devtools-protocol/}
Expand Down Expand Up @@ -180,13 +174,6 @@ export type OwnE2edConfig<
*/
pathToScreenshotsDirectoryForReport: string | null;

/**
* Path to TypeScript config file of the project from the root directory of the project.
* The project should have one common TypeScript config for both
* the application code and the autotest code.
*/
pathToTsConfigOfProjectFromRoot: string;

/**
* The name of the file under which, after running the tests,
* the HTML report will be saved in the `autotests/reports` directory, for example, `report.html`.
Expand Down
1 change: 1 addition & 0 deletions src/types/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type E2edEnvironment = {
[key: string]: string | undefined;
['E2ED_DEBUG']?: string;
['E2ED_ORIGIN']?: string;
['E2ED_PATH_TO_TS_CONFIG_OF_PROJECT_FROM_ROOT']?: string;
[PATH_TO_PACK_VARIABLE_NAME]?: string;
['PWD']?: string;
[RUN_ENVIRONMENT_VARIABLE_NAME]?: RunEnvironment;
Expand Down
10 changes: 5 additions & 5 deletions src/utils/clone/cloneWithoutLogEvents.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
type WithLogEvents = {logEvents: unknown};
type WithLogEvents = Readonly<{logEvents: unknown}>;

/**
* Clone test run object without logEvents property (to reduce logs).
* Clone test run object without `logEvents` property (to reduce logs).
* @internal
*/
export const cloneWithoutLogEvents = <T extends WithLogEvents>(
withLogEvents: T,
): Omit<T, 'logEvents'> => {
export const cloneWithoutLogEvents = <Type extends WithLogEvents>(
withLogEvents: Type,
): Omit<Type, 'logEvents'> => {
const {logEvents, ...withoutLogEvents} = withLogEvents ?? {};

void logEvents;
Expand Down
52 changes: 52 additions & 0 deletions src/utils/environment/getDotEnvValuesObject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {readFile} from 'node:fs/promises';

import {DOT_ENV_PATH, READ_FILE_OPTIONS} from '../../constants/internal';

import {E2edError} from '../error';

/**
* Get object with values from `.env` file in directory with autotests.
* {@link https://www.npmjs.com/package/dotenv}
* @internal
*/
export const getDotEnvValuesObject = async (): Promise<Readonly<Record<string, string>>> => {
const dotEnvText = await readFile(DOT_ENV_PATH, READ_FILE_OPTIONS);

const lines = dotEnvText.split('\n');
const result = Object.create(null) as Record<string, string>;

for (const line of lines) {
const trimmedLine = line.trim();

if (line === '' || line[0] === '#') {
continue;
}

const indexOfEqualSign = trimmedLine.indexOf('=');

if (indexOfEqualSign < 1) {
throw new E2edError('Incorrect name of environment variable in `.env`', {line});
}

const name = trimmedLine.slice(0, indexOfEqualSign).trim();

if (name in result) {
throw new E2edError(`Duplicate name "${name}" in \`.env\` file`, {
firstValue: result[name],
line,
});
}

const valueMaybeWithQuotes = trimmedLine.slice(indexOfEqualSign + 1).trim();
const firstCharacter = valueMaybeWithQuotes[0];
const isQuoted =
firstCharacter === valueMaybeWithQuotes.at(-1) &&
(firstCharacter === '"' || firstCharacter === "'" || firstCharacter === '`');

const value = isQuoted ? valueMaybeWithQuotes.slice(1, -1) : valueMaybeWithQuotes;

result[name] = value;
}

return result;
};
2 changes: 2 additions & 0 deletions src/utils/environment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
export {getPathToPack, setPathToPack} from './pathToPack';
/** @internal */
export {getRunLabel, setRunLabel} from './runLabel';
/** @internal */
export {setDotEnvValuesToEnvironment} from './setDotEnvValuesToEnvironment';
29 changes: 29 additions & 0 deletions src/utils/environment/setDotEnvValuesToEnvironment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {e2edEnvironment} from '../../constants/internal';

import {E2edError} from '../error';

import {getDotEnvValuesObject} from './getDotEnvValuesObject';

/**
* Set values from `.env` file in directory with autotests to environment (to `process.env`).
* @internal
*/
export const setDotEnvValuesToEnvironment = async (): Promise<void> => {
// eslint-disable-next-line @typescript-eslint/unbound-method
const {hasOwnProperty} = Object.prototype;
const values = await getDotEnvValuesObject();

for (const [name, value] of Object.entries(values)) {
if (hasOwnProperty.call(e2edEnvironment, name) && e2edEnvironment[name] !== value) {
throw new E2edError(
`Environment variable "${name}" from \`.env\` already defined in \`process.env\` with other value`,
{
valueFromDotEnv: value,
valueFromProccessEnv: e2edEnvironment[name],
},
);
}

e2edEnvironment[name] = value;
}
};
24 changes: 22 additions & 2 deletions src/utils/events/registerStartE2edRunEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import {RunEnvironment} from '../../configurator';
import {EVENTS_DIRECTORY_PATH, ExitCode, TMP_DIRECTORY_PATH} from '../../constants/internal';

import {getFullPackConfig, updateConfig} from '../config';
import {getPathToPack, setDotEnvValuesToEnvironment} from '../environment';
import {E2edError} from '../error';
import {setGlobalExitCode} from '../exit';
import {createDirectory, removeDirectory, writeStartInfo} from '../fs';
import {generalLog, writeLogsToFile} from '../generalLog';
import {compilePack, setPackTimeout} from '../pack';
import {setPackTimeout} from '../pack';
import {compilePack} from '../packCompiler';
import {getStartInfo} from '../startInfo';

import {runBeforePackFunctions} from './runBeforePackFunctions';
Expand All @@ -19,7 +21,13 @@ export const registerStartE2edRunEvent = async (): Promise<void> => {
await removeDirectory(TMP_DIRECTORY_PATH);
await createDirectory(EVENTS_DIRECTORY_PATH);

compilePack();
let errorSettingDotEnv: unknown;

await setDotEnvValuesToEnvironment().catch((error: unknown) => {
errorSettingDotEnv = error;
});

const compileErrors = compilePack();

const startInfo = getStartInfo();

Expand All @@ -35,6 +43,18 @@ export const registerStartE2edRunEvent = async (): Promise<void> => {

updateConfig(fullPackConfig, startInfo);

if (errorSettingDotEnv) {
generalLog('Caught an error on setting environment variables from `.env` file', {
errorSettingDotEnv,
});
}

if (compileErrors.length !== 0) {
const pathToPack = getPathToPack();

generalLog(`Caught errors on compiling pack ${pathToPack}`, {compileErrors});
}

const {e2ed, runEnvironment} = startInfo;
const isDockerRun = runEnvironment === RunEnvironment.Docker;
const startMessage = `Run tests ${isDockerRun ? 'in docker' : 'local'} with e2ed@${e2ed.version}`;
Expand Down
Loading

0 comments on commit 41bb7c7

Please sign in to comment.