Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
20a7d6c
feat!: add generic e2e support to check-store workflow
May 19, 2026
a7d8e30
fix: refine generic e2e workflow orchestration
May 19, 2026
863eab5
fix: guard remaining e2e runtime setup steps
May 19, 2026
3dea50b
fix: combined both checks package.json and e2e folder existence to tr…
May 19, 2026
9962aea
fix: refine e2e suite detection and orchestration flow
May 20, 2026
9a67bff
Remove unecessary code
May 22, 2026
ff27265
fix: add sample data and e2e suite bootstrap
Jun 2, 2026
f4a8d43
refactor: remove e2e workflow guards during validation
Jun 3, 2026
f5ad7cd
Fix matrix reference in check-store workflow
damienwebdev Jun 3, 2026
4bdd58b
feat(resolve-check-config): add support for check-store e2e-tests
damienwebdev Jun 10, 2026
26413af
fix a bad rebase
damienwebdev Jun 10, 2026
c456442
fix: fallback to npm install when lockfile is missing
Jun 11, 2026
b388bed
Merge branch 'graycoreio:main' into feat/check-store-e2e-support
digitalrisedorset Jun 18, 2026
71c20be
fix: bootstrap E2E suite from cloned MageOS repository
Jun 18, 2026
d16b002
feat: bootstrap Playwright E2E suite for Check Store
Jun 18, 2026
56451eb
debug: inspect E2E suite installation in CI
Jun 18, 2026
36f1e8e
chore: remove temporary E2E debugging
Jun 18, 2026
c80125c
ci(e2e): split initial Playwright smoke tests
Jun 18, 2026
1e4e25b
fix(ci): run Playwright tests from E2E working directory
Jun 18, 2026
cdc0bf8
feat(ci): publish Playwright reports and test artifacts
Jun 23, 2026
ed78052
feat(ci): install Playwright browsers with system dependencies
Jun 23, 2026
b343d06
chore(ci): enable E2E setup steps for debugging
Jun 23, 2026
765f6ed
chore(ci): remove E2E step conditions for debugging
Jun 24, 2026
0ab7aed
chore(ci): use Node.js 22 for E2E workflow
Jun 25, 2026
2beb482
chore(ci): use Node.js 24 for E2E workflow
Jun 25, 2026
a136e0c
chore(ci): remove npm cache from E2E setup
Jun 25, 2026
fff299f
chore(ci): ensure Magento writable directories exist
Jun 25, 2026
a1908be
chore(ci): ensure Magento writable directories exist
Jun 25, 2026
e6c4c19
feat(ci): add reusable Magento CLI action
Jul 1, 2026
cf83ea7
feat(ci): use temporary include path to use the run-command-repository
Jul 1, 2026
b648409
feat(ci): use temporary include path to use the run-command-repository
Jul 1, 2026
3a2f219
feat(ci): use temporary include path to use the run-command-repository
Jul 1, 2026
8e74d4c
chore(ci): run Magento CLI commands via docker exec
Jul 1, 2026
26b2aea
Merge branch 'graycoreio:main' into feature/ci-magento-runtime
digitalrisedorset Jul 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/_internal-check-store.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,19 @@ jobs:
env:
COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }}

- name: Opt in to e2e-test
working-directory: ${{ steps.setup-magento.outputs.path }}
run: |
mkdir -p .github
echo '{ "jobs": { "e2e-test": true } }' > .github/check-store.json
- uses: actions/upload-artifact@v7
with:
name: store-fixture-${{ matrix.version }}
path: |
${{ steps.setup-magento.outputs.path }}
!${{ steps.setup-magento.outputs.path }}/vendor
include-hidden-files: true
retention-days: 3

check-store:
Expand Down
163 changes: 161 additions & 2 deletions .github/workflows/check-store.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,13 @@ jobs:
kind: custom
custom_versions: ${{ steps.get-magento-version.outputs.project }}:${{ fromJSON(steps.get-magento-version.outputs.version) }}

- uses: graycoreio/github-actions-magento2/resolve-check-config@main
## TODO: restore to graycoreio/github-actions-magento2/resolve-check-config@main before merge
- uses: digitalrisedorset/github-actions-magento2/resolve-check-config@feat/check-store-e2e-support
id: resolve
with:
kind: store
matrix: ${{ steps.supported-version.outputs.matrix }}
config_path: ${{ inputs.path }}/.github/check-store.json

unit-test:
runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -246,4 +248,161 @@ jobs:
- uses: graycoreio/github-actions-magento2/smoke-test@main
if: contains(fromJSON(needs.compute_matrix.outputs.resolved)['smoke-test'].probes, 'graphql')
with:
kind: graphql
kind: graphql

e2e-test:
runs-on: ${{ matrix.os }}
needs: compute_matrix
if: ${{ fromJSON(needs.compute_matrix.outputs.resolved)['e2e-test'].enabled != false }}
services: ${{ matrix.services }}
strategy:
matrix: ${{ fromJSON(needs.compute_matrix.outputs.resolved)['e2e-test'].matrix }}

steps:
- uses: actions/checkout@v6
if: inputs.store_artifact_name == ''

- uses: actions/download-artifact@v8
if: inputs.store_artifact_name != ''
with:
name: ${{ inputs.store_artifact_name }}
path: ${{ inputs.path }}

- uses: graycoreio/github-actions-magento2/setup-magento@main
id: setup-magento
with:
php-version: ${{ matrix.php }}
tools: composer:v${{ matrix.composer }}
mode: store
working-directory: ${{ inputs.path }}
composer_auth: ${{ secrets.composer_auth }}

- name: Detect E2E npm contract
id: detect-e2e
working-directory: ${{ steps.setup-magento.outputs.path }}
run: |
if [ -d dev/tests/e2e ] \
&& [ "$(find dev/tests/e2e -type f | wc -l)" -gt 0 ] \
&& [ -f package.json ]; then
echo "enabled=true" >> "$GITHUB_OUTPUT"
else
echo "enabled=false" >> "$GITHUB_OUTPUT"
echo "::notice::No package.json found, skipping E2E"
fi

- uses: graycoreio/github-actions-magento2/cache-magento@main
with:
composer_cache_key: ${{ inputs.composer_cache_key }}
working-directory: ${{ steps.setup-magento.outputs.path }}
stamp: ${{ inputs.stamp }}

- name: Composer install
working-directory: ${{ steps.setup-magento.outputs.path }}
run: composer install
env:
COMPOSER_AUTH: ${{ secrets.composer_auth }}

- uses: graycoreio/github-actions-magento2/setup-install@main
id: setup-install
with:
services: ${{ toJSON(matrix.services) }}
path: ${{ steps.setup-magento.outputs.path }}
container_id: ${{ job.services['php-fpm'].id }}
extra_args: --magento-init-params=MAGE_MODE=developer

- uses: graycoreio/github-actions-magento2/configure-service-nginx@main
with:
container_id: ${{ job.services.nginx.id }}
magento_path: ${{ inputs.path }}

- uses: actions/setup-node@v4
with:
node-version: 24

# TODO:
# setup-install already executes Magento CLI commands through `docker exec`.
# Consider extracting this pattern into a reusable `run-magento-command`
# action once the E2E workflow has stabilised.
- name: Install Magento sample data
working-directory: ${{ steps.setup-magento.outputs.path }}
run: |
docker exec \
-w /var/www/html/${{ steps.setup-magento.outputs.path }} \
${{ job.services['php-fpm'].id }} \
php bin/magento sampledata:deploy

composer update

docker exec \
-w /var/www/html/${{ steps.setup-magento.outputs.path }} \
${{ job.services['php-fpm'].id }} \
php bin/magento setup:upgrade

docker exec \
-w /var/www/html/${{ steps.setup-magento.outputs.path }} \
${{ job.services['php-fpm'].id }} \
php bin/magento indexer:reindex

- name: Install MageOS E2E suite
working-directory: ${{ steps.setup-magento.outputs.path }}
run: |
mkdir -p dev/tests

git clone \
--branch ci/tests-e2e-playwright-elgentos-hyva \
https://github.com/digitalrisedorset/mageos-magento2.git \
mageos-elgentos-e2e

mv mageos-elgentos-e2e/dev/tests/e2e dev/tests/
rm -rf mageos-elgentos-e2e

- name: Generate E2E .env
working-directory: ${{ steps.setup-magento.outputs.path }}/dev/tests/e2e
# values below come from setup-install/src/build-command.ts and should be refactored later
run: |
cat > .env <<EOF
PLAYWRIGHT_BASE_URL=http://localhost/
PLAYWRIGHT_PRODUCTION_URL=http://localhost/
PLAYWRIGHT_REVIEW_URL=http://localhost/
MAGENTO_ADMIN_SLUG=admin
MAGENTO_ADMIN_USERNAME=admin
MAGENTO_ADMIN_PASSWORD=admin123
MAGENTO_THEME_LOCALE=en_US
EOF

- name: Run E2E tests
working-directory: ${{ steps.setup-magento.outputs.path }}/dev/tests/e2e
run: |
if [ -f package-lock.json ]; then
npm ci
else
npm install
fi

npx playwright install --with-deps chromium
npx playwright test tests/healthcheck.spec.ts

- name: E2E Healthcheck
working-directory: ${{ steps.setup-magento.outputs.path }}/dev/tests/e2e
run: npx playwright test tests/healthcheck.spec.ts

- name: E2E Home
working-directory: ${{ steps.setup-magento.outputs.path }}/dev/tests/e2e
run: npx playwright test tests/home.spec.ts

- name: E2E Category
working-directory: ${{ steps.setup-magento.outputs.path }}/dev/tests/e2e
run: npx playwright test tests/category.spec.ts

- name: E2E Product
working-directory: ${{ steps.setup-magento.outputs.path }}/dev/tests/e2e
run: npx playwright test tests/product.spec.ts

- name: Upload Playwright artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-artifacts
path: |
${{ steps.setup-magento.outputs.path }}/dev/tests/e2e/playwright-report
${{ steps.setup-magento.outputs.path }}/dev/tests/e2e/test-results
9 changes: 9 additions & 0 deletions _test/demo-package/Test/E2E/ItWorksTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const testItWorks = (): string => {
return "Hello world";
};

if (testItWorks() !== "Hello world") {
process.exit(1);
}

console.log("E2E test passed");
6 changes: 5 additions & 1 deletion resolve-check-config/check-store.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
"properties": {
"unit-test": { "$ref": "#/$defs/jobConfig" },
"coding-standard": { "$ref": "#/$defs/jobConfig" },
"smoke-test": { "$ref": "#/$defs/smokeJobConfig" }
"smoke-test": { "$ref": "#/$defs/smokeJobConfig" },
"e2e-test": {
"$ref": "#/$defs/jobConfig",
"description": "Opt-in: e2e-test does not run unless enabled here."
}
},
"additionalProperties": false
}
Expand Down
87 changes: 51 additions & 36 deletions resolve-check-config/dist/index.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions resolve-check-config/examples/check-store.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"jobs": {
"unit-test": true,
"coding-standard": true,
"e2e-test": true,
"integration-test": {
"services": ["search", "queue", "cache"]
},
Expand Down
29 changes: 27 additions & 2 deletions resolve-check-config/src/kinds/store.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const MATRIX: Matrix = {

describe('STORE_JOBS', () => {
it('declares the check-store jobs', () => {
expect(Object.keys(STORE_JOBS).sort()).toEqual(['coding-standard', 'smoke-test', 'unit-test']);
expect(Object.keys(STORE_JOBS).sort()).toEqual(['coding-standard', 'e2e-test', 'smoke-test', 'unit-test']);
});

it('declares smoke-test required tiers (end-user cannot toggle)', () => {
Expand All @@ -35,6 +35,16 @@ describe('STORE_JOBS', () => {
expect(STORE_JOBS['smoke-test'].probes).toEqual(['page']);
});

it('declares e2e-test required tiers (end-user cannot toggle)', () => {
expect(STORE_JOBS['e2e-test'].services).toEqual([]);
expect([...STORE_JOBS['e2e-test'].requiredServices!].sort()).toEqual([
'cache',
'db',
'search',
'web',
]);
});

it('exposes empty service defaults for unit-test and coding-standard', () => {
expect(STORE_JOBS['unit-test'].services).toEqual([]);
expect(STORE_JOBS['coding-standard'].services).toEqual([]);
Expand All @@ -48,7 +58,7 @@ describe('STORE_JOBS', () => {
describe('resolveStoreConfig', () => {
it('emits every known job with default tier expansion, always including mysql for smoke-test', () => {
const resolved = resolveStoreConfig({}, MATRIX);
expect(Object.keys(resolved).sort()).toEqual(['coding-standard', 'smoke-test', 'unit-test']);
expect(Object.keys(resolved).sort()).toEqual(['coding-standard', 'e2e-test', 'smoke-test', 'unit-test']);
expect(resolved['unit-test'].matrix.include[0].services).toEqual({});
expect(Object.keys(resolved['smoke-test'].matrix.include[0].services!).sort()).toEqual([
'mysql',
Expand All @@ -75,6 +85,21 @@ describe('resolveStoreConfig', () => {
]);
});

it('disables e2e-test by default (opt-in job)', () => {
const resolved = resolveStoreConfig({}, MATRIX);
expect(resolved['e2e-test'].enabled).toBe(false);
expect(resolved['unit-test'].enabled).toBe(true);
expect(resolved['smoke-test'].enabled).toBe(true);
});

it('enables e2e-test when the caller opts in', () => {
const resolved = resolveStoreConfig(
{ jobs: { 'e2e-test': true } },
MATRIX,
);
expect(resolved['e2e-test'].enabled).toBe(true);
});

it('honors enabled=false for a job', () => {
const resolved = resolveStoreConfig(
{ jobs: { 'smoke-test': false } },
Expand Down
5 changes: 5 additions & 0 deletions resolve-check-config/src/kinds/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export const STORE_JOBS: Record<string, JobDefaults> = {
requiredServices: ['db', 'search', 'queue', 'cache', 'web'],
probes: ['page'],
},
'e2e-test': {
services: [],
requiredServices: ['db', 'search', 'cache', 'web'],
enabledByDefault: false,
},
};

export const KNOWN_JOBS_STORE: readonly string[] = Object.keys(STORE_JOBS);
Expand Down
2 changes: 1 addition & 1 deletion resolve-check-config/src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const normalizeJobEntry = (
defaults: JobDefaults,
): { enabled: boolean; tiers: readonly Tier[]; probes?: readonly Probe[] } => {
if (raw === undefined) {
return { enabled: true, tiers: defaults.services, probes: defaults.probes };
return { enabled: defaults.enabledByDefault ?? true, tiers: defaults.services, probes: defaults.probes };
}
if (typeof raw === 'boolean') {
return { enabled: raw, tiers: defaults.services, probes: defaults.probes };
Expand Down
4 changes: 4 additions & 0 deletions resolve-check-config/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,15 @@ export interface Matrix {
* `probes` is the default smoke-test probe list used when the caller
* does not override it. Only jobs that declare it support the
* `probes` config key; omit it for jobs that have no probe concept.
* `enabledByDefault` controls the `enabled` value emitted when the
* caller's config omits the job entirely. Defaults to `true`; set
* `false` for opt-in jobs.
*/
export interface JobDefaults {
services: readonly Tier[];
requiredServices?: readonly Tier[];
probes?: readonly Probe[];
enabledByDefault?: boolean;
}

/**
Expand Down
18 changes: 18 additions & 0 deletions run-magento-command/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Run Magento Command

Runs `php bin/magento` inside the configured PHP container.

## Inputs

- container_id
- path
- command

## Example

```yaml
- uses: graycoreio/github-actions-magento2/run-magento-command@main
with:
container_id: ...
path: ...
command: cache:flush
32 changes: 32 additions & 0 deletions run-magento-command/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: "Run Magento command"
author: "Graycore"
description: "Executes a Magento CLI command inside the PHP service container."

inputs:
container_id:
description: "PHP container ID"
required: true

path:
description: "Magento root path inside the PHP container"
required: false
default: "."

command:
description: "Magento CLI arguments, e.g. 'cache:flush' or 'setup:upgrade --keep-generated'"
required: true

runs:
using: "node24"
main: "dist/index.js"

branding:
icon: "terminal"
color: "gray-dark"

outputs:
stdout:
description: "Standard output of the Magento command"

exit_code:
description: "Exit code of the command"
9 changes: 9 additions & 0 deletions run-magento-command/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
clearMocks: true,
moduleFileExtensions: ['js', 'ts'],
testMatch: ['**/*.spec.ts'],
transform: {
'^.+\\.ts$': 'ts-jest'
},
verbose: true
}
Loading