From e7fca45f4bf9cfed79dae5d5a4f03de7961d3e71 Mon Sep 17 00:00:00 2001 From: Jontze <42588836+jontze@users.noreply.github.com> Date: Sat, 2 Nov 2024 16:33:29 +0100 Subject: [PATCH] chore: Setup e2e tests for example and execute in CI --- .github/workflows/test.yaml | 24 +++++++ apps/ng-remote-config-example/e2e/app.spec.ts | 59 ++++++++++++++++ .../e2e/config-asset.spec.ts | 13 ++++ .../e2e/features-asset.spec.ts | 13 ++++ apps/ng-remote-config-example/jest.config.ts | 1 + .../playwright.config.ts | 69 +++++++++++++++++++ .../src/app/app.component.html | 4 +- apps/ng-remote-config-example/src/index.html | 2 +- 8 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 apps/ng-remote-config-example/e2e/app.spec.ts create mode 100644 apps/ng-remote-config-example/e2e/config-asset.spec.ts create mode 100644 apps/ng-remote-config-example/e2e/features-asset.spec.ts create mode 100644 apps/ng-remote-config-example/playwright.config.ts diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index aa63f62..e7990a8 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -31,6 +31,29 @@ jobs: - name: Test run: npx nx affected -t test + e2e: + runs-on: ubuntu-latest + name: E2E + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: nrwl/nx-set-shas@v4 + with: + main-branch-name: ${{ env.MAIN_BRANCH_NAME }} + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'npm' + - name: Install Dependencies + run: npm ci + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: E2E + run: npx nx affected -t e2e + lint: runs-on: ubuntu-latest name: Lint @@ -80,6 +103,7 @@ jobs: - test - lint - format + - e2e outputs: uploaded-artifact: ${{ steps.artifact-upload.outputs.artifact-id != ''}} steps: diff --git a/apps/ng-remote-config-example/e2e/app.spec.ts b/apps/ng-remote-config-example/e2e/app.spec.ts new file mode 100644 index 0000000..bcd1134 --- /dev/null +++ b/apps/ng-remote-config-example/e2e/app.spec.ts @@ -0,0 +1,59 @@ +import { test, expect } from '@playwright/test'; + +test('Has Browser Tab Title', async ({ page }) => { + await page.goto('/'); + + expect(await page.title()).toBe('NG-Remote-Config Example'); +}); + +test('Has Title', async ({ page }) => { + await page.goto('/'); + + expect(await page.locator('h1').innerText()).toContain( + 'NG-Remote-Config Example' + ); +}); + +test("Has JSON Viewer for 'config.json'", async ({ page }) => { + await page.goto('/'); + + expect(await page.locator('h2').first().innerText()).toContain('Config'); + await expect(page.locator('app-editor').first()).toBeVisible(); +}); + +test('Has same config as in config.json', async ({ page, request }) => { + const response = await request.get('/assets/config.json'); + expect(response.status()).toBe(200); + + const configJson = await response.json(); + const configString = JSON.stringify(configJson, null, 2); // Formatting similar to the JSON pipe + + await page.goto('/'); + + const renderedJson = await page.locator('pre').first().textContent(); + + expect(renderedJson?.trim()).toBe(configString); +}); + +test("Has JSON Viewer for 'features.json'", async ({ page }) => { + await page.goto('/'); + + expect(await page.locator('h2').last().innerText()).toContain( + 'Feature Flags' + ); + await expect(page.locator('app-editor').last()).toBeVisible(); +}); + +test('Has same config as in features.json', async ({ page, request }) => { + const response = await request.get('/assets/features.json'); + expect(response.status()).toBe(200); + + const configJson = await response.json(); + const configString = JSON.stringify(configJson, null, 2); // Formatting similar to the JSON pipe + + await page.goto('/'); + + const renderedJson = await page.locator('pre').last().textContent(); + + expect(renderedJson?.trim()).toBe(configString); +}); diff --git a/apps/ng-remote-config-example/e2e/config-asset.spec.ts b/apps/ng-remote-config-example/e2e/config-asset.spec.ts new file mode 100644 index 0000000..9f0a4f5 --- /dev/null +++ b/apps/ng-remote-config-example/e2e/config-asset.spec.ts @@ -0,0 +1,13 @@ +import { test, expect } from '@playwright/test'; + +test('has config file present and valid JSON', async ({ request }) => { + const response = await request.get('/assets/config.json'); + + expect(response.status()).toBe(200); + + const responseBody = await response.text(); + expect(() => JSON.parse(responseBody)).not.toThrow(); + + const json = JSON.parse(responseBody); + expect(json).toHaveProperty('environment'); +}); diff --git a/apps/ng-remote-config-example/e2e/features-asset.spec.ts b/apps/ng-remote-config-example/e2e/features-asset.spec.ts new file mode 100644 index 0000000..db6d490 --- /dev/null +++ b/apps/ng-remote-config-example/e2e/features-asset.spec.ts @@ -0,0 +1,13 @@ +import { test, expect } from '@playwright/test'; + +test('has feature config file present and valid JSON', async ({ request }) => { + const response = await request.get('/assets/features.json'); + + expect(response.status()).toBe(200); + + const responseBody = await response.text(); + expect(() => JSON.parse(responseBody)).not.toThrow(); + + const json = JSON.parse(responseBody); + expect(json).toHaveProperty('isFeatureEnabled'); +}); diff --git a/apps/ng-remote-config-example/jest.config.ts b/apps/ng-remote-config-example/jest.config.ts index 063ce3b..ecf7a14 100644 --- a/apps/ng-remote-config-example/jest.config.ts +++ b/apps/ng-remote-config-example/jest.config.ts @@ -13,6 +13,7 @@ export default { }, ], }, + testPathIgnorePatterns: ['/e2e/'], transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], snapshotSerializers: [ 'jest-preset-angular/build/serializers/no-ng-attributes', diff --git a/apps/ng-remote-config-example/playwright.config.ts b/apps/ng-remote-config-example/playwright.config.ts new file mode 100644 index 0000000..78806f4 --- /dev/null +++ b/apps/ng-remote-config-example/playwright.config.ts @@ -0,0 +1,69 @@ +import { defineConfig, devices } from '@playwright/test'; +import { nxE2EPreset } from '@nx/playwright/preset'; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { workspaceRoot } from '@nx/devkit'; + +// For CI, you may want to set BASE_URL to the deployed application. +const baseURL = process.env['BASE_URL'] || 'http://localhost:4200'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + ...nxE2EPreset(__filename, { testDir: './e2e' }), + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + baseURL, + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + /* Run your local dev server before starting the tests */ + webServer: { + command: 'nx run ng-remote-config-example:serve', + url: 'http://localhost:4200', + reuseExistingServer: !process.env.CI, + cwd: workspaceRoot, + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + + // Uncomment for mobile browsers support + /* { + name: 'Mobile Chrome', + use: { ...devices['Pixel 5'] }, + }, + { + name: 'Mobile Safari', + use: { ...devices['iPhone 12'] }, + }, */ + + // Uncomment for branded browsers + /* { + name: 'Microsoft Edge', + use: { ...devices['Desktop Edge'], channel: 'msedge' }, + }, + { + name: 'Google Chrome', + use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + } */ + ], +}); diff --git a/apps/ng-remote-config-example/src/app/app.component.html b/apps/ng-remote-config-example/src/app/app.component.html index c66ea8b..5f8cfb6 100644 --- a/apps/ng-remote-config-example/src/app/app.component.html +++ b/apps/ng-remote-config-example/src/app/app.component.html @@ -15,8 +15,8 @@

Config

Feature Flags

-
- +
+ {{ featureFlags() | json }}
diff --git a/apps/ng-remote-config-example/src/index.html b/apps/ng-remote-config-example/src/index.html index 976bc06..d52b7e0 100644 --- a/apps/ng-remote-config-example/src/index.html +++ b/apps/ng-remote-config-example/src/index.html @@ -2,7 +2,7 @@ - ng-async-config + NG-Remote-Config Example