mirror of
https://github.com/strapi/strapi.git
synced 2025-11-13 00:29:51 +00:00
Merge branch 'develop' into fix-scaleway-docs
This commit is contained in:
commit
b7ac2016ea
3
.github/actions/run-e2e-tests/action.yml
vendored
3
.github/actions/run-e2e-tests/action.yml
vendored
@ -5,6 +5,8 @@ inputs:
|
||||
description: 'Should run EE or CE e2e tests'
|
||||
jestOptions:
|
||||
description: 'Jest options'
|
||||
enableFutureFeatures:
|
||||
description: 'Enable future unstable features'
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
@ -12,4 +14,5 @@ runs:
|
||||
env:
|
||||
RUN_EE: ${{ inputs.runEE }}
|
||||
JEST_OPTIONS: ${{ inputs.jestOptions }}
|
||||
STRAPI_FEATURES_FUTURE_RELEASES_SCHEDULING: ${{ inputs.enableFutureFeatures }}
|
||||
shell: bash
|
||||
|
||||
5
.github/workflows/tests.yml
vendored
5
.github/workflows/tests.yml
vendored
@ -189,7 +189,7 @@ jobs:
|
||||
if: failure()
|
||||
with:
|
||||
name: ce-playwright-trace
|
||||
path: test-apps/e2e/**/test-results/**/trace.zip
|
||||
path: test-apps/e2e/test-results/**/trace.zip
|
||||
retention-days: 1
|
||||
|
||||
e2e_ee:
|
||||
@ -225,13 +225,14 @@ jobs:
|
||||
uses: ./.github/actions/run-e2e-tests
|
||||
with:
|
||||
runEE: true
|
||||
enableFutureFeatures: true
|
||||
jestOptions: --project=${{ matrix.project }}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: ee-playwright-trace
|
||||
path: test-apps/e2e/**/test-results/**/trace.zip
|
||||
path: test-apps/e2e/test-results/**/trace.zip
|
||||
retention-days: 1
|
||||
|
||||
api_ce_pg:
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -146,6 +146,7 @@ front-workspace.code-workspace
|
||||
playwright-report
|
||||
test-results
|
||||
!e2e/data/*.tar
|
||||
e2e/.env
|
||||
|
||||
############################
|
||||
# Strapi
|
||||
|
||||
@ -29,6 +29,46 @@ This will spawn by default a Strapi instance per testing domain (e.g. content-ma
|
||||
|
||||
If you need to clean the test-apps folder because they are not working as expected, you can run `yarn test:e2e clean` which will clean said directory.
|
||||
|
||||
### Running specific tests
|
||||
|
||||
To run only one domain, meaning a top-level directory in e2e/tests such as "admin" or "content-manager", use the `--domains` option.
|
||||
|
||||
```shell
|
||||
yarn test:e2e --domains admin
|
||||
yarn test:e2e --domain admin
|
||||
```
|
||||
|
||||
To run a specific file, you can pass arguments and options to playwright using `--` between the test:e2e options and the playwright options, such as:
|
||||
|
||||
```shell
|
||||
# to run just the login.spec.ts file in the admin domain
|
||||
yarn test:e2e --domains admin -- login.spec.ts
|
||||
```
|
||||
|
||||
### Concurrency / parallellization
|
||||
|
||||
By default, every domain is run with its own test app in parallel with the other domains. The tests within a domain are run in series, one at a time.
|
||||
|
||||
If you need an easier way to view the output, or have problems running multiple apps at once on your system, you can use the `-c` option
|
||||
|
||||
```shell
|
||||
# only run one domain at a time
|
||||
yarn test:e2e -c 1
|
||||
```
|
||||
|
||||
### Env Variables to Control Test Config
|
||||
|
||||
Some helpers have been added to allow you to modify the playwright configuration on your own system without touching the playwright config file used by the test runner.
|
||||
|
||||
| env var | Description | Default |
|
||||
| ---------------------------- | -------------------------------------------- | ------------------ |
|
||||
| PLAYWRIGHT_WEBSERVER_TIMEOUT | timeout for starting the Strapi server | 16000 (160s) |
|
||||
| PLAYWRIGHT_ACTION_TIMEOUT | playwright action timeout (ie, click()) | 15000 (15s) |
|
||||
| PLAYWRIGHT_EXPECT_TIMEOUT | playwright expect waitFor timeout | 10000 (10s) |
|
||||
| PLAYWRIGHT_TIMEOUT | playwright timeout, for each individual test | 30000 (30s) |
|
||||
| PLAYWRIGHT_OUTPUT_DIR | playwright output dir, such as trace files | '../test-results/' |
|
||||
| PLAYWRIGHT_VIDEO | set 'true' to save videos on failed tests | false |
|
||||
|
||||
## Strapi Templates
|
||||
|
||||
The test-app you create uses a [template](https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/installation/templates.html) found at `e2e/app-template` in this folder we can store our premade content schemas & any customisations we may need such as other plugins / custom fields / endpoints etc.
|
||||
@ -41,6 +81,14 @@ Playwright enables reliable end-to-end testing for modern web apps. It's cross b
|
||||
|
||||
For more information check out their [docs](https://playwright.dev/docs/intro). If you're struggling with their APIs, then check out their specific [API documentation](https://playwright.dev/docs/api/class-playwright).
|
||||
|
||||
## Running tests with environment variables
|
||||
|
||||
To set specific environment variables for your tests, a `.env` file can be created in the root of the e2e folder. This is useful if you need to run tests with a Strapi license or set future flags.
|
||||
|
||||
## Running tests with future flags
|
||||
|
||||
If you are writing tests for an unstable future feature you will need to add `app-template/config/features.js`. Currently the app template generation does not take the config folder into consideration. However, the run-e2e-tests script will apply the features config to the generated app. See the documentation for [features.js](https://docs.strapi.io/dev-docs/configurations/features#enabling-a-future-flag)
|
||||
|
||||
## What makes a good end to end test?
|
||||
|
||||
This is the million dollar question. E2E tests typically test complete user flows that touch numerous points of the application it's testing, we're not interested in what happens during a process, only the user perspective and end results. Consider writing them with your story hat on. E.g. "As a user I want to create a new entity, publish that entity, and then be able to retrieve its data from the content API".
|
||||
|
||||
3
e2e/README.md
Normal file
3
e2e/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
## End-to-end Playwright Tests
|
||||
|
||||
See contributor docs in docs/docs/guides/e2e for more info
|
||||
5
e2e/app-template/config/features.js
Normal file
5
e2e/app-template/config/features.js
Normal file
@ -0,0 +1,5 @@
|
||||
module.exports = ({ env }) => ({
|
||||
future: {
|
||||
contentReleasesScheduling: env.bool('STRAPI_FEATURES_FUTURE_RELEASES_SCHEDULING', false),
|
||||
},
|
||||
});
|
||||
@ -10,13 +10,6 @@ describeOnCondition(edition === 'EE')('Releases page', () => {
|
||||
await resetDatabaseAndImportDataFromPath('./e2e/data/with-admin.tar');
|
||||
await page.goto('/admin');
|
||||
await login({ page });
|
||||
|
||||
await page.evaluate(() => {
|
||||
// Remove after Scheduling Beta release
|
||||
window.strapi.future = {
|
||||
isEnabled: () => true,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
test('A user should be able to create a release without scheduling it and view their pending and done releases', async ({
|
||||
@ -70,7 +63,17 @@ describeOnCondition(edition === 'EE')('Releases page', () => {
|
||||
name: 'Date',
|
||||
})
|
||||
.click();
|
||||
await page.getByRole('gridcell', { name: 'Sunday, March 3, 2024' }).click();
|
||||
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() + 1);
|
||||
const formattedDate = date.toLocaleDateString('en-US', {
|
||||
weekday: 'long',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
});
|
||||
|
||||
await page.getByRole('gridcell', { name: formattedDate }).click();
|
||||
|
||||
await page
|
||||
.getByRole('combobox', {
|
||||
|
||||
@ -60,6 +60,8 @@ import {
|
||||
import { useTypedDispatch } from '../store/hooks';
|
||||
import { getTimezoneOffset } from '../utils/time';
|
||||
|
||||
import { getBadgeProps } from './ReleasesPage';
|
||||
|
||||
import type {
|
||||
ReleaseAction,
|
||||
ReleaseActionGroupBy,
|
||||
@ -350,7 +352,13 @@ export const ReleaseDetailsLayout = ({
|
||||
<HeaderLayout
|
||||
title={release.name}
|
||||
subtitle={
|
||||
numberOfEntriesText + (IsSchedulingEnabled && isScheduled ? ` - ${scheduledText}` : '')
|
||||
<Flex gap={2} lineHeight={6}>
|
||||
<Typography textColor="neutral600" variant="epsilon">
|
||||
{numberOfEntriesText +
|
||||
(IsSchedulingEnabled && isScheduled ? ` - ${scheduledText}` : '')}
|
||||
</Typography>
|
||||
<Badge {...getBadgeProps(release.status)}>{release.status}</Badge>
|
||||
</Flex>
|
||||
}
|
||||
navigationAction={
|
||||
<Link startIcon={<ArrowLeft />} to="/plugins/content-releases">
|
||||
|
||||
@ -4,6 +4,7 @@ import * as React from 'react';
|
||||
import { useLicenseLimits } from '@strapi/admin/strapi-admin';
|
||||
import {
|
||||
Alert,
|
||||
Badge,
|
||||
Box,
|
||||
Button,
|
||||
ContentLayout,
|
||||
@ -39,7 +40,7 @@ import { useIntl } from 'react-intl';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { GetReleases } from '../../../shared/contracts/releases';
|
||||
import { GetReleases, type Release } from '../../../shared/contracts/releases';
|
||||
import { ReleaseModal, FormValues } from '../components/ReleaseModal';
|
||||
import { PERMISSIONS } from '../constants';
|
||||
import { isAxiosError } from '../services/axios';
|
||||
@ -62,6 +63,37 @@ const LinkCard = styled(Link)`
|
||||
display: block;
|
||||
`;
|
||||
|
||||
const CapitalizeRelativeTime = styled(RelativeTime)`
|
||||
text-transform: capitalize;
|
||||
`;
|
||||
|
||||
const getBadgeProps = (status: Release['status']) => {
|
||||
let color;
|
||||
switch (status) {
|
||||
case 'ready':
|
||||
color = 'success';
|
||||
break;
|
||||
case 'blocked':
|
||||
color = 'warning';
|
||||
break;
|
||||
case 'failed':
|
||||
color = 'danger';
|
||||
break;
|
||||
case 'done':
|
||||
color = 'primary';
|
||||
break;
|
||||
case 'empty':
|
||||
default:
|
||||
color = 'neutral';
|
||||
}
|
||||
|
||||
return {
|
||||
textColor: `${color}600`,
|
||||
backgroundColor: `${color}100`,
|
||||
borderColor: `${color}200`,
|
||||
};
|
||||
};
|
||||
|
||||
const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }: ReleasesGridProps) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const IsSchedulingEnabled = window.strapi.future.isEnabled('contentReleasesScheduling');
|
||||
@ -89,7 +121,7 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }: Releases
|
||||
|
||||
return (
|
||||
<Grid gap={4}>
|
||||
{releases.map(({ id, name, actions, scheduledAt }) => (
|
||||
{releases.map(({ id, name, actions, scheduledAt, status }) => (
|
||||
<GridItem col={3} s={6} xs={12} key={id}>
|
||||
<LinkCard href={`content-releases/${id}`} isExternal={false}>
|
||||
<Flex
|
||||
@ -102,15 +134,16 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }: Releases
|
||||
height="100%"
|
||||
width="100%"
|
||||
alignItems="start"
|
||||
gap={2}
|
||||
gap={4}
|
||||
>
|
||||
<Flex direction="column" alignItems="start" gap={1}>
|
||||
<Typography as="h3" variant="delta" fontWeight="bold">
|
||||
{name}
|
||||
</Typography>
|
||||
<Typography variant="pi" textColor="neutral600">
|
||||
{IsSchedulingEnabled ? (
|
||||
scheduledAt ? (
|
||||
<RelativeTime timestamp={new Date(scheduledAt)} />
|
||||
<CapitalizeRelativeTime timestamp={new Date(scheduledAt)} />
|
||||
) : (
|
||||
formatMessage({
|
||||
id: 'content-releases.pages.Releases.not-scheduled',
|
||||
@ -129,6 +162,8 @@ const ReleasesGrid = ({ sectionTitle, releases = [], isError = false }: Releases
|
||||
)}
|
||||
</Typography>
|
||||
</Flex>
|
||||
<Badge {...getBadgeProps(status)}>{status}</Badge>
|
||||
</Flex>
|
||||
</LinkCard>
|
||||
</GridItem>
|
||||
))}
|
||||
@ -405,4 +440,4 @@ const ReleasesPage = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export { ReleasesPage };
|
||||
export { ReleasesPage, getBadgeProps };
|
||||
|
||||
@ -52,6 +52,9 @@ describe('Releases details page', () => {
|
||||
const releaseSubtitle = await screen.findAllByText('No entries');
|
||||
expect(releaseSubtitle[0]).toBeInTheDocument();
|
||||
|
||||
const releaseStatus = screen.getByText('empty');
|
||||
expect(releaseStatus).toBeInTheDocument();
|
||||
|
||||
const moreButton = screen.getByRole('button', { name: 'Release edit and delete menu' });
|
||||
expect(moreButton).toBeInTheDocument();
|
||||
|
||||
@ -146,7 +149,7 @@ describe('Releases details page', () => {
|
||||
expect(tables).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('shows the right status', async () => {
|
||||
it('shows the right status for unpublished release', async () => {
|
||||
server.use(
|
||||
rest.get('/content-releases/:releaseId', (req, res, ctx) =>
|
||||
res(ctx.json(mockReleaseDetailsPageData.withActionsHeaderData))
|
||||
@ -160,7 +163,7 @@ describe('Releases details page', () => {
|
||||
);
|
||||
|
||||
render(<ReleaseDetailsPage />, {
|
||||
initialEntries: [{ pathname: `/content-releases/1` }],
|
||||
initialEntries: [{ pathname: `/content-releases/2` }],
|
||||
});
|
||||
|
||||
const releaseTitle = await screen.findByText(
|
||||
@ -168,6 +171,10 @@ describe('Releases details page', () => {
|
||||
);
|
||||
expect(releaseTitle).toBeInTheDocument();
|
||||
|
||||
const releaseStatus = screen.getByText('ready');
|
||||
expect(releaseStatus).toBeInTheDocument();
|
||||
expect(releaseStatus).toHaveStyle(`color: #328048`);
|
||||
|
||||
const cat1Row = screen.getByRole('row', { name: /cat1/i });
|
||||
expect(within(cat1Row).getByRole('gridcell', { name: 'Ready to publish' })).toBeInTheDocument();
|
||||
|
||||
@ -181,4 +188,31 @@ describe('Releases details page', () => {
|
||||
within(add1Row).getByRole('gridcell', { name: 'Already published' })
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the right release status for published release', async () => {
|
||||
server.use(
|
||||
rest.get('/content-releases/:releaseId', (req, res, ctx) =>
|
||||
res(ctx.json(mockReleaseDetailsPageData.withActionsAndPublishedHeaderData))
|
||||
)
|
||||
);
|
||||
|
||||
server.use(
|
||||
rest.get('/content-releases/:releaseId/actions', (req, res, ctx) =>
|
||||
res(ctx.json(mockReleaseDetailsPageData.withMultipleActionsBodyData))
|
||||
)
|
||||
);
|
||||
|
||||
render(<ReleaseDetailsPage />, {
|
||||
initialEntries: [{ pathname: `/content-releases/3` }],
|
||||
});
|
||||
|
||||
const releaseTitle = await screen.findByText(
|
||||
mockReleaseDetailsPageData.withActionsAndPublishedHeaderData.data.name
|
||||
);
|
||||
expect(releaseTitle).toBeInTheDocument();
|
||||
|
||||
const releaseStatus = screen.getByText('done');
|
||||
expect(releaseStatus).toBeInTheDocument();
|
||||
expect(releaseStatus).toHaveStyle(`color: #4945ff`);
|
||||
});
|
||||
});
|
||||
|
||||
@ -9,6 +9,7 @@ const RELEASE_NO_ACTIONS_HEADER_MOCK_DATA = {
|
||||
createdAt: '2023-11-16T15:18:32.560Z',
|
||||
updatedAt: '2023-11-16T15:18:32.560Z',
|
||||
releasedAt: null,
|
||||
status: 'empty',
|
||||
createdBy: {
|
||||
id: 1,
|
||||
firstname: 'Admin',
|
||||
@ -50,6 +51,7 @@ const RELEASE_WITH_ACTIONS_HEADER_MOCK_DATA = {
|
||||
createdAt: '2023-11-16T15:18:32.560Z',
|
||||
updatedAt: '2023-11-16T15:18:32.560Z',
|
||||
releasedAt: null,
|
||||
status: 'ready',
|
||||
createdBy: {
|
||||
id: 1,
|
||||
firstname: 'Admin',
|
||||
@ -70,11 +72,12 @@ const RELEASE_WITH_ACTIONS_HEADER_MOCK_DATA = {
|
||||
|
||||
const PUBLISHED_RELEASE_WITH_ACTIONS_HEADER_MOCK_DATA = {
|
||||
data: {
|
||||
id: 2,
|
||||
id: 3,
|
||||
name: 'release with actions',
|
||||
createdAt: '2023-11-16T15:18:32.560Z',
|
||||
updatedAt: '2023-11-16T15:18:32.560Z',
|
||||
releasedAt: '2023-11-16T15:18:32.560Z',
|
||||
status: 'done',
|
||||
createdBy: {
|
||||
id: 1,
|
||||
firstname: 'Admin',
|
||||
|
||||
@ -12,6 +12,7 @@ interface CustomInterval {
|
||||
export interface RelativeTimeProps {
|
||||
timestamp: Date;
|
||||
customIntervals?: CustomInterval[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -28,7 +29,7 @@ export interface RelativeTimeProps {
|
||||
* ]}
|
||||
* ```
|
||||
*/
|
||||
const RelativeTime = ({ timestamp, customIntervals = [] }: RelativeTimeProps) => {
|
||||
const RelativeTime = ({ timestamp, customIntervals = [], className }: RelativeTimeProps) => {
|
||||
const { formatRelativeTime, formatDate, formatTime } = useIntl();
|
||||
|
||||
const interval = intervalToDuration({
|
||||
@ -54,6 +55,7 @@ const RelativeTime = ({ timestamp, customIntervals = [] }: RelativeTimeProps) =>
|
||||
<time
|
||||
dateTime={timestamp.toISOString()}
|
||||
title={`${formatDate(timestamp)} ${formatTime(timestamp)}`}
|
||||
className={className}
|
||||
>
|
||||
{displayText}
|
||||
</time>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// @ts-check
|
||||
const { devices } = require('@playwright/test');
|
||||
const { parseType } = require('@strapi/utils');
|
||||
|
||||
const getEnvNum = (envVar, defaultValue) => {
|
||||
if (envVar !== undefined && envVar !== null) {
|
||||
@ -8,6 +9,22 @@ const getEnvNum = (envVar, defaultValue) => {
|
||||
return defaultValue;
|
||||
};
|
||||
|
||||
const getEnvString = (envVar, defaultValue) => {
|
||||
if (envVar?.trim().length) {
|
||||
return envVar;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
};
|
||||
|
||||
const getEnvBool = (envVar, defaultValue) => {
|
||||
if (!envVar || envVar === '') {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return parseType({ type: 'boolean', value: envVar.toLowerCase() });
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef ConfigOptions
|
||||
* @type {{ port: number; testDir: string; appDir: string }}
|
||||
@ -28,7 +45,7 @@ const createConfig = ({ port, testDir, appDir }) => ({
|
||||
* Maximum time expect() should wait for the condition to be met.
|
||||
* For example in `await expect(locator).toHaveText();`
|
||||
*/
|
||||
timeout: getEnvNum(process.env.PLAYWRIGHT_EXPECT_TIMEOUT, 30 * 1000),
|
||||
timeout: getEnvNum(process.env.PLAYWRIGHT_EXPECT_TIMEOUT, 10 * 1000),
|
||||
},
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: false,
|
||||
@ -46,13 +63,22 @@ const createConfig = ({ port, testDir, appDir }) => ({
|
||||
baseURL: `http://127.0.0.1:${port}`,
|
||||
|
||||
/* Default time each action such as `click()` can take to 20s */
|
||||
actionTimeout: getEnvNum(process.env.PLAYWRIGHT_ACTION_TIMEOUT, 20 * 1000),
|
||||
actionTimeout: getEnvNum(process.env.PLAYWRIGHT_ACTION_TIMEOUT, 15 * 1000),
|
||||
|
||||
/* Collect trace when a test failed on the CI. See https://playwright.dev/docs/trace-viewer
|
||||
Until https://github.com/strapi/strapi/issues/18196 is fixed we can't enable this locally,
|
||||
because the Strapi server restarts every time a new file (trace) is created.
|
||||
*/
|
||||
trace: process.env.CI ? 'retain-on-failure' : 'off',
|
||||
trace: 'retain-on-failure',
|
||||
video: getEnvBool(process.env.PLAYWRIGHT_VIDEO, false)
|
||||
? {
|
||||
mode: 'retain-on-failure', // 'retain-on-failure' to save videos only for failed tests
|
||||
size: {
|
||||
width: 1280,
|
||||
height: 720,
|
||||
},
|
||||
}
|
||||
: 'off',
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
@ -80,7 +106,7 @@ const createConfig = ({ port, testDir, appDir }) => ({
|
||||
],
|
||||
|
||||
/* Folder for test artifacts such as screenshots, videos, traces, etc. */
|
||||
outputDir: 'test-results/',
|
||||
outputDir: getEnvString(process.env.PLAYWRIGHT_OUTPUT_DIR, '../test-results/'), // in the test-apps/e2e dir, to avoid writing files to the running Strapi project dir
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
webServer: {
|
||||
|
||||
@ -5,12 +5,55 @@ const execa = require('execa');
|
||||
const fs = require('node:fs/promises');
|
||||
const yargs = require('yargs');
|
||||
|
||||
const chalk = require('chalk');
|
||||
const dotenv = require('dotenv');
|
||||
const { cleanTestApp, generateTestApp } = require('../helpers/test-app');
|
||||
const { createConfig } = require('../../playwright.base.config');
|
||||
const chalk = require('chalk');
|
||||
|
||||
const cwd = path.resolve(__dirname, '../..');
|
||||
const testAppDirectory = path.join(cwd, 'test-apps', 'e2e');
|
||||
const testRoot = path.join(cwd, 'e2e');
|
||||
const templateDir = path.join(testRoot, 'app-template');
|
||||
|
||||
const pathExists = async (path) => {
|
||||
try {
|
||||
await fs.access(path);
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the env file for a generated test app
|
||||
* - Removes the PORT key/value from generated app .env
|
||||
* - Uses e2e/app-template/config/features.js to enable future features in the generated app
|
||||
*/
|
||||
const setupTestEnvironment = async (generatedAppPath) => {
|
||||
/**
|
||||
* Because we're running multiple test apps at the same time
|
||||
* and the env file is generated by the generator with no way
|
||||
* to override it, we manually remove the PORT key/value so when
|
||||
* we set it further down for each playwright instance it works.
|
||||
*/
|
||||
const pathToEnv = path.join(generatedAppPath, '.env');
|
||||
const envFile = (await fs.readFile(pathToEnv)).toString();
|
||||
const envWithoutPort = envFile.replace('PORT=1337', '');
|
||||
await fs.writeFile(pathToEnv, envWithoutPort);
|
||||
|
||||
/*
|
||||
* Enable future features in the generated app manually since a template
|
||||
* does not allow the config folder.
|
||||
*/
|
||||
const testRootFeaturesConfigPath = path.join(templateDir, 'config', 'features.js');
|
||||
const hasFeaturesConfig = await pathExists(testRootFeaturesConfigPath);
|
||||
|
||||
if (!hasFeaturesConfig) return;
|
||||
|
||||
const configFeatures = await fs.readFile(testRootFeaturesConfigPath);
|
||||
const appFeaturesConfigPath = path.join(generatedAppPath, 'config', 'features.js');
|
||||
await fs.writeFile(appFeaturesConfigPath, configFeatures);
|
||||
};
|
||||
|
||||
yargs
|
||||
.parserConfiguration({
|
||||
@ -51,6 +94,11 @@ yargs
|
||||
},
|
||||
handler: async (argv) => {
|
||||
try {
|
||||
if (await pathExists(path.join(testRoot, '.env'))) {
|
||||
// Run tests with the env variables specified in the e2e/app-template/.env
|
||||
dotenv.config({ path: path.join(testRoot, '.env') });
|
||||
}
|
||||
|
||||
const { concurrency, domains, setup } = argv;
|
||||
|
||||
/**
|
||||
@ -109,16 +157,8 @@ yargs
|
||||
template: path.join(cwd, 'e2e', 'app-template'),
|
||||
link: true,
|
||||
});
|
||||
/**
|
||||
* Because we're running multiple test apps at the same time
|
||||
* and the env file is generated by the generator with no way
|
||||
* to override it, we manually remove the PORT key/value so when
|
||||
* we set it further down for each playwright instance it works.
|
||||
*/
|
||||
const pathToEnv = path.join(appPath, '.env');
|
||||
const envFile = (await fs.readFile(pathToEnv)).toString();
|
||||
const envWithoutPort = envFile.replace('PORT=1337', '');
|
||||
await fs.writeFile(pathToEnv, envWithoutPort);
|
||||
|
||||
await setupTestEnvironment(appPath);
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user