From 0f0c704f19a98ad700a2072207a8f738eb64ed91 Mon Sep 17 00:00:00 2001 From: Svana Date: Wed, 13 Nov 2024 11:15:20 +0000 Subject: [PATCH 01/18] feat: Move web e2e tests to web app directory --- apps/web/e2e/smoke/homepage.spec.ts | 146 ++++++++++++++++++ apps/web/e2e/smoke/search.spec.ts | 58 +++++++ .../e2e/smoke/sites-of-institutions.spec.ts | 80 ++++++++++ apps/web/e2e/utils/addons.ts | 40 +++++ apps/web/playwright.config.ts | 11 ++ apps/web/project.json | 6 + 6 files changed, 341 insertions(+) create mode 100644 apps/web/e2e/smoke/homepage.spec.ts create mode 100644 apps/web/e2e/smoke/search.spec.ts create mode 100644 apps/web/e2e/smoke/sites-of-institutions.spec.ts create mode 100644 apps/web/e2e/utils/addons.ts create mode 100644 apps/web/playwright.config.ts diff --git a/apps/web/e2e/smoke/homepage.spec.ts b/apps/web/e2e/smoke/homepage.spec.ts new file mode 100644 index 000000000000..b0819fd6b418 --- /dev/null +++ b/apps/web/e2e/smoke/homepage.spec.ts @@ -0,0 +1,146 @@ +import { + BrowserContext, + expect, + session, + test, + urls, +} from '@island.is/testing/e2e' + +test.use({ baseURL: urls.islandisBaseUrl }) + +test.describe('Front page', () => { + let context: BrowserContext + test.beforeAll(async ({ browser }) => { + context = await session({ + browser: browser, + storageState: 'homepage.json', + homeUrl: `${urls.islandisBaseUrl}/`, + phoneNumber: '0103019', + idsLoginOn: false, + }) + }) + test.afterAll(async () => { + await context.close() + }) + test('has expected sections @lang:is', async () => { + const page = await context.newPage() + await page.goto('/') + await expect( + page.locator('text=Öll opinber þjónusta á einum stað'), + ).toBeVisible() + await expect(page.locator('data-testid=home-banner')).toBeVisible() + await expect(page.locator('data-testid=home-heading')).toBeVisible() + await expect(page.locator('data-testid=home-news')).toBeVisible() + }) + + for (const { lang, home } of [ + { lang: 'is', home: '/' }, + { lang: 'en', home: '/en' }, + ]) { + test(`should have life event @lang:${lang}`, async () => { + test.slow() + const page = await context.newPage() + await page.goto(home) + const lifeEventsCards = page.locator('[data-testid="lifeevent-card"]') + + await expect(lifeEventsCards).toHaveCountGreaterThan(3) + const lifeEventHandles = await lifeEventsCards.elementHandles() + const lifeEventUrls = await Promise.all( + lifeEventHandles.map((item) => item.getAttribute('href')), + ) + for (const url of lifeEventUrls) { + const page = await context.newPage() + const result = await page.goto(url!) + await expect( + page.getByRole('link', { name: 'island.is logo' }), + ).toBeVisible() + expect(result!.status()).toBe(200) + await page.close() + } + }) + test(`should navigate to featured link @lang:${lang}`, async () => { + test.slow() + const page = await context.newPage() + await page.goto(home) + const featuredLinks = page.locator('[data-testid="featured-link"]') + await expect(featuredLinks).toHaveCountGreaterThan(3) + const featuredLinksHandles = await featuredLinks.elementHandles() + const featuresLinksUrls = await Promise.all( + featuredLinksHandles.map((item) => item.getAttribute('href')), + ) + for (const url of featuresLinksUrls) { + const page = await context.newPage() + const result = await page.goto(url!) + await expect( + page.getByRole('link', { name: 'island.is logo' }), + ).toBeVisible() + expect(result!.status()).toBe(200) + await page.close() + } + }) + + test(`should have link on life events pages to navigate back to the main page @lang:${lang}`, async () => { + test.slow() + const page = await context.newPage() + await page.goto(home) + const lifeEventsCards = page.locator('[data-testid="lifeevent-card"]') + const lifeEventHandles = await lifeEventsCards.elementHandles() + const lifeEventUrls = await Promise.all( + lifeEventHandles.map((item) => item.getAttribute('href')), + ) + for (const url of lifeEventUrls) { + const page = await context.newPage() + const result = await page.goto(url!) + expect(result?.url()).not.toBe(home) + await page.locator('[data-testid="link-back-home"]').click() + await expect(page.locator('data-testid=home-heading')).toBeVisible() + await expect(page).toHaveURL(home) + await page.close() + } + }) + } + + test('should change welcome message on language toggle @lang:is', async () => { + const page = await context.newPage() + await page.goto('/') + const homeHeading = page.locator('h1[data-testid="home-heading"]') + const icelandicHeading = await homeHeading.textContent() + await page.locator('button[data-testid="language-toggler"]:visible').click() + await expect(homeHeading).not.toHaveText(icelandicHeading!) + await expect(page).toHaveURL('/en') + }) + + test('should toggle mega-menu @lang:is', async () => { + const page = await context.newPage() + await page.goto('/') + await page + .locator('[data-testid="frontpage-burger-button"]:nth-child(2)') + .click() + await expect( + page.locator('[data-testid="mega-menu-link"] > a'), + ).toHaveCountGreaterThan(18) + }) + + test('burger menu should open and close', async () => { + // Arrange + const page = await context.newPage() + page.goto('/') + await page.getByRole('button', { name: 'Valmynd' }).click() + + // Act + await expect(page.getByRole('dialog', { name: 'Menu' })).toBeVisible() + await expect( + page.getByRole('paragraph').filter({ hasText: 'Þjónustuflokkar' }), + ).toBeVisible() + await expect(page.getByRole('dialog', { name: 'Menu' })).toBeVisible() + // Heading is "visible" behind menu + // await expect(page.getByTestId('home-heading')).not.toBeVisible() + await page + .getByRole('dialog', { name: 'Menu' }) + .getByRole('button') + .getByTestId('icon-close') + .click() + await expect(page.getByTestId('home-heading')).toBeVisible() + await expect(page.getByRole('dialog', { name: 'Menu' })).not.toBeVisible() + }) +}) diff --git a/apps/web/e2e/smoke/search.spec.ts b/apps/web/e2e/smoke/search.spec.ts new file mode 100644 index 000000000000..c0bffb617641 --- /dev/null +++ b/apps/web/e2e/smoke/search.spec.ts @@ -0,0 +1,58 @@ +import { + BrowserContext, + expect, + session, + test, + urls, +} from '@island.is/testing/e2e' + +test.use({ baseURL: urls.islandisBaseUrl }) + +test.describe('Search feature', () => { + let context: BrowserContext + test.beforeAll(async ({ browser }) => { + context = await session({ + browser: browser, + storageState: 'homepage.json', + homeUrl: `${urls.islandisBaseUrl}/`, + phoneNumber: '0103019', + idsLoginOn: false, + }) + }) + test.afterAll(async () => { + await context.close() + }) + + test('has expected sections', async () => { + const testPhrase = 'umsókn' + const page = await context.newPage() + await page.goto('/') + await page + .getByRole('textbox', { name: 'Leitaðu á Ísland.is' }) + .type(testPhrase, { delay: 100 }) + await page.keyboard.press('Enter') + const testResults = page.locator('[data-testid="search-result"]') + await expect(testResults).toHaveCountGreaterThan(9) + const searchUrl = page.url() + await testResults.nth(0).click() + await page.waitForLoadState('networkidle') + await expect(page).not.toHaveURL(searchUrl) + }) + + test('should have no search results for long bogus search words', async () => { + const page = await context.newPage() + await page.goto('/') + await page.type( + 'role=textbox[name="Leitaðu á Ísland.is"]', + 'abcdefhijklmnopqrstuvwxyz1234567890', + ) + await page.keyboard.press('Enter') + await page.waitForLoadState('networkidle') + const testResults = page.locator('[data-testid="search-result"]') + await expect(testResults).toHaveCount(0) + }) + + test.skip('should search in Enlish', async () => { + return + }) +}) diff --git a/apps/web/e2e/smoke/sites-of-institutions.spec.ts b/apps/web/e2e/smoke/sites-of-institutions.spec.ts new file mode 100644 index 000000000000..88e33e925564 --- /dev/null +++ b/apps/web/e2e/smoke/sites-of-institutions.spec.ts @@ -0,0 +1,80 @@ +import slugify from 'slugify' + +import { + BrowserContext, + expect, + Page, + session, + test, + urls, +} from '@island.is/testing/e2e' + +type GetByRole = Pick['getByRole'] +type GetByRoleParameters = Parameters + +test.use({ baseURL: urls.islandisBaseUrl }) +type Orgs = { + organisationName: string + organisationHome?: string + enabled?: boolean + target?: { role: GetByRoleParameters[0]; options?: GetByRoleParameters[1] } +} +const orgs: Orgs[] = [ + { organisationName: 'Opinberir aðilar', organisationHome: '/' }, + { organisationName: 'Fiskistofa' }, + { + organisationName: 'Heilbrigðisstofnun Norðurlands', + organisationHome: '/hsn', + }, + { organisationName: 'Sjúkratryggingar', target: { role: 'link' } }, + { organisationName: 'Ríkislögmaður' }, + { organisationName: 'Landskjörstjórn', target: { role: 'link' } }, + { organisationName: 'Opinber nýsköpun', enabled: true }, + { organisationName: 'Sýslumenn' }, + { organisationName: 'Fjársýslan' }, + { + organisationName: 'Heilbrigðisstofnun Suðurlands', + organisationHome: '/hsu', + }, + { + organisationName: 'Landlæknir', + target: { role: 'link', options: { name: 'Eyðublöð' } }, + }, + { organisationName: 'Útlendingastofnun', target: { role: 'link' } }, +] + +test.describe('Sites of institutions', () => { + let context: BrowserContext + test.beforeAll(async ({ browser }) => { + context = await session({ + browser, + idsLoginOn: false, + homeUrl: '/s', + }) + }) + test.afterAll(async () => { + await context.close() + }) + for (const { + organisationName, + organisationHome = `/${slugify(organisationName, { lower: true })}`, + target, + enabled, + } of orgs) { + test(organisationName, async () => { + if (enabled) return + const page = await context.newPage() + const url = `/s${organisationHome}` + await page.goto(url) + await expect( + page + .getByRole(target?.role ?? 'heading', { + ...{ name: organisationName }, + ...target?.options, + }) + .first(), + ).toBeVisible() + await page.close() + }) + } +}) diff --git a/apps/web/e2e/utils/addons.ts b/apps/web/e2e/utils/addons.ts new file mode 100644 index 000000000000..e012fa9e99ac --- /dev/null +++ b/apps/web/e2e/utils/addons.ts @@ -0,0 +1,40 @@ +import { expect, Locator, Page, sleep } from '@island.is/testing/e2e' + +expect.extend({ + async toHaveCountGreaterThan( + received: Locator, + value: number, + options: { timeout: number; sleepTime: number } = { + timeout: 10000, + sleepTime: 100, + }, + ) { + const initialTime = Date.now() + let count = -1 + while (count <= value) { + count = await received.count() + if (Date.now() > initialTime + options.timeout) + return { message: () => 'Timeout', pass: false } + await sleep(options.sleepTime) + } + return { + message: () => `Found ${count} elements`, + pass: true, + } + }, + async toBeApplication(received: string | Page, applicationType = '\\w+') { + const url: string = typeof received == 'string' ? received : received.url() + const protocol = 'https?://' + const host = '[^/]+' + const applicationId = '(/(\\w|-)*)?' + const applicationRegExp = new RegExp( + `^${protocol}${host}/umsoknir/${applicationType}${applicationId}$`, + ) + const pass = applicationRegExp.test(url) + const message = () => + `Current page is ${pass ? '' : '*not* '}an application + Pattern ${applicationRegExp} + URL is ${url}` + return { message, pass } + }, +}) diff --git a/apps/web/playwright.config.ts b/apps/web/playwright.config.ts new file mode 100644 index 000000000000..435dc6f9a54d --- /dev/null +++ b/apps/web/playwright.config.ts @@ -0,0 +1,11 @@ +import { createPlaywrightConfig } from '@island.is/testing/e2e' + +import './e2e/utils/addons' + +const webConfig = createPlaywrightConfig({ + webServerUrl: 'http://localhost:4200', + command: 'yarn dev-init web && source .env.secret && yarn dev web', + cwd: '../../', +}) + +export default webConfig diff --git a/apps/web/project.json b/apps/web/project.json index cc84a6ffdf79..9c2c9ffc8282 100644 --- a/apps/web/project.json +++ b/apps/web/project.json @@ -138,6 +138,12 @@ }, "docker-next": { "executor": "Intentionally left blank, only so this target is valid when using `nx show projects --with-target docker-next`" + }, + "e2e": { + "executor": "@nx/playwright:playwright", + "options": { + "config": "{projectRoot}/playwright.config.ts" + } } } } From 05e489f7c0b0ded63e35c0a206d38da3a6cbbc35 Mon Sep 17 00:00:00 2001 From: Svana Date: Thu, 14 Nov 2024 23:11:52 +0000 Subject: [PATCH 02/18] Remove e2e from jest and improve tests --- apps/web/README.md | 8 + apps/web/e2e/smoke/homepage.spec.ts | 219 ++++++++++++------ apps/web/e2e/smoke/search.spec.ts | 13 +- .../e2e/smoke/sites-of-institutions.spec.ts | 17 +- apps/web/jest.config.ts | 1 + apps/web/playwright.config.ts | 2 +- libs/testing/e2e/src/lib/helpers/api-tools.ts | 18 +- 7 files changed, 194 insertions(+), 84 deletions(-) diff --git a/apps/web/README.md b/apps/web/README.md index 6d182d440515..31eec864aecc 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -90,6 +90,14 @@ yarn nx extract-strings web Currently, in this project, only the `Custom Page` content type utilizes the `Translation Namespace` content type for translations +### Starting e2e tests locally + +You can start the e2e tests by running: + +```bash +yarn e2e web +``` + ## Further Documentation [Subpages](./docs/subpages.md) - Information on Layouts and Components used when diff --git a/apps/web/e2e/smoke/homepage.spec.ts b/apps/web/e2e/smoke/homepage.spec.ts index b0819fd6b418..ca1f5d6da928 100644 --- a/apps/web/e2e/smoke/homepage.spec.ts +++ b/apps/web/e2e/smoke/homepage.spec.ts @@ -1,5 +1,6 @@ import { BrowserContext, + createPageAndNavigate, expect, session, test, @@ -10,6 +11,7 @@ test.use({ baseURL: urls.islandisBaseUrl }) test.describe('Front page', () => { let context: BrowserContext + test.beforeAll(async ({ browser }) => { context = await session({ browser: browser, @@ -19,12 +21,13 @@ test.describe('Front page', () => { idsLoginOn: false, }) }) + test.afterAll(async () => { await context.close() }) + test('has expected sections @lang:is', async () => { - const page = await context.newPage() - await page.goto('/') + const page = await createPageAndNavigate(context, '/') await expect( page.locator('text=Öll opinber þjónusta á einum stað'), ).toBeVisible() @@ -33,101 +36,177 @@ test.describe('Front page', () => { await expect(page.locator('data-testid=home-news')).toBeVisible() }) - for (const { lang, home } of [ - { lang: 'is', home: '/' }, - { lang: 'en', home: '/en' }, - ]) { - test(`should have life event @lang:${lang}`, async () => { - test.slow() - const page = await context.newPage() - await page.goto(home) - const lifeEventsCards = page.locator('[data-testid="lifeevent-card"]') + test(`should have life event @lang:is`, async () => { + test.slow() + const page = await createPageAndNavigate(context, '/') + const lifeEventsCards = page.locator('[data-testid="lifeevent-card"]') + await expect(lifeEventsCards.count()).resolves.toBeGreaterThan(3) + const lifeEventHandles = await lifeEventsCards.elementHandles() + const lifeEventUrls = await Promise.all( + lifeEventHandles.map((item) => item.getAttribute('href')), + ) + const lifeEventPage = await context.newPage() + for (const url of lifeEventUrls) { + const result = await lifeEventPage.goto(url ?? '') + await expect( + lifeEventPage.getByRole('link', { name: 'island.is logo' }), + ).toBeVisible() + expect(result?.status()).toBe(200) + } + await lifeEventPage.close() + }) + + test(`should have life event @lang:en`, async () => { + test.slow() + const page = await createPageAndNavigate(context, '/en') + const lifeEventsCards = page.locator('[data-testid="lifeevent-card"]') + await expect(lifeEventsCards.count()).resolves.toBeGreaterThan(3) + const lifeEventHandles = await lifeEventsCards.elementHandles() + const lifeEventUrls = await Promise.all( + lifeEventHandles.map((item) => item.getAttribute('href')), + ) + const lifeEventPage = await context.newPage() + for (const url of lifeEventUrls) { + const result = await lifeEventPage.goto(url ?? '') + await expect( + lifeEventPage.getByRole('link', { name: 'island.is logo' }), + ).toBeVisible() + expect(result?.status()).toBe(200) + } + await lifeEventPage.close() + }) - await expect(lifeEventsCards).toHaveCountGreaterThan(3) - const lifeEventHandles = await lifeEventsCards.elementHandles() - const lifeEventUrls = await Promise.all( - lifeEventHandles.map((item) => item.getAttribute('href')), - ) - for (const url of lifeEventUrls) { - const page = await context.newPage() - const result = await page.goto(url!) + test(`should navigate to featured link @lang:is`, async () => { + if (!context) { + throw new Error('Context is not initialized') + } + test.slow() + const page = await createPageAndNavigate(context, '/') + const featuredLinks = page.locator('[data-testid="featured-link"]') + await expect(featuredLinks.count()).resolves.toBeGreaterThan(3) + const featuredLinksHandles = await featuredLinks.elementHandles() + const featuresLinksUrls = await Promise.all( + featuredLinksHandles.map((item) => item.getAttribute('href')), + ) + const featuredPage = await context.newPage() + for (const url of featuresLinksUrls) { + if (url) { + const result = await featuredPage.goto(url) await expect( - page.getByRole('link', { name: 'island.is logo' }), + featuredPage.getByRole('link', { name: 'island.is logo' }), ).toBeVisible() - expect(result!.status()).toBe(200) - await page.close() + if (result) { + expect(result.status()).toBe(200) + } } - }) - test(`should navigate to featured link @lang:${lang}`, async () => { - test.slow() - const page = await context.newPage() - await page.goto(home) - const featuredLinks = page.locator('[data-testid="featured-link"]') - await expect(featuredLinks).toHaveCountGreaterThan(3) - const featuredLinksHandles = await featuredLinks.elementHandles() - const featuresLinksUrls = await Promise.all( - featuredLinksHandles.map((item) => item.getAttribute('href')), - ) - for (const url of featuresLinksUrls) { - const page = await context.newPage() - const result = await page.goto(url!) + } + await featuredPage.close() + }) + + test(`should navigate to featured link @lang:en`, async () => { + if (!context) { + throw new Error('Context is not initialized') + } + test.slow() + const page = await createPageAndNavigate(context, '/en') + const featuredLinks = page.locator('[data-testid="featured-link"]') + await expect(featuredLinks.count()).resolves.toBeGreaterThan(3) + const featuredLinksHandles = await featuredLinks.elementHandles() + const featuresLinksUrls = await Promise.all( + featuredLinksHandles.map((item) => item.getAttribute('href')), + ) + const featuredPage = await context.newPage() + for (const url of featuresLinksUrls) { + if (url) { + const result = await featuredPage.goto(url) await expect( - page.getByRole('link', { name: 'island.is logo' }), + featuredPage.getByRole('link', { name: 'island.is logo' }), ).toBeVisible() - expect(result!.status()).toBe(200) - await page.close() + if (result) { + expect(result.status()).toBe(200) + } } - }) + } + await featuredPage.close() + }) - test(`should have link on life events pages to navigate back to the main page @lang:${lang}`, async () => { - test.slow() - const page = await context.newPage() - await page.goto(home) - const lifeEventsCards = page.locator('[data-testid="lifeevent-card"]') - const lifeEventHandles = await lifeEventsCards.elementHandles() - const lifeEventUrls = await Promise.all( - lifeEventHandles.map((item) => item.getAttribute('href')), - ) - for (const url of lifeEventUrls) { - const page = await context.newPage() - const result = await page.goto(url!) - expect(result?.url()).not.toBe(home) - await page.locator('[data-testid="link-back-home"]').click() - await expect(page.locator('data-testid=home-heading')).toBeVisible() - await expect(page).toHaveURL(home) - await page.close() + test(`should have link on life events pages to navigate back to the main page @lang:is`, async () => { + if (!context) { + throw new Error('Context is not initialized') + } + test.slow() + const page = await createPageAndNavigate(context, '/') + const lifeEventsCards = page.locator('[data-testid="lifeevent-card"]') + const lifeEventHandles = await lifeEventsCards.elementHandles() + const lifeEventUrls = await Promise.all( + lifeEventHandles.map((item) => item.getAttribute('href')), + ) + const lifeEventPage = await context.newPage() + for (const url of lifeEventUrls) { + if (url) { + await lifeEventPage.goto(url) + await lifeEventPage.locator('[data-testid="link-back-home"]').click() } - }) - } + await lifeEventPage.locator('[data-testid="link-back-home"]').click() + await expect( + lifeEventPage.locator('data-testid=home-heading'), + ).toBeVisible() + await expect(lifeEventPage).toHaveURL('/') + } + await lifeEventPage.close() + }) + + test(`should have link on life events pages to navigate back to the main page @lang:en`, async () => { + if (!context) { + throw new Error('Context is not initialized') + } + test.slow() + const page = await createPageAndNavigate(context, '/en') + const lifeEventsCards = page.locator('[data-testid="lifeevent-card"]') + const lifeEventHandles = await lifeEventsCards.elementHandles() + const lifeEventUrls = await Promise.all( + lifeEventHandles.map((item) => item.getAttribute('href')), + ) + const lifeEventPage = await context.newPage() + for (const url of lifeEventUrls) { + if (url) { + await lifeEventPage.goto(url) + await lifeEventPage.locator('[data-testid="link-back-home"]').click() + } + await lifeEventPage.locator('[data-testid="link-back-home"]').click() + await expect( + lifeEventPage.locator('data-testid=home-heading'), + ).toBeVisible() + await expect(lifeEventPage).toHaveURL('/en') + } + await lifeEventPage.close() + }) test('should change welcome message on language toggle @lang:is', async () => { - const page = await context.newPage() - await page.goto('/') + const page = await createPageAndNavigate(context, '/') const homeHeading = page.locator('h1[data-testid="home-heading"]') const icelandicHeading = await homeHeading.textContent() await page.locator('button[data-testid="language-toggler"]:visible').click() - await expect(homeHeading).not.toHaveText(icelandicHeading!) + if (icelandicHeading) { + await expect(homeHeading).not.toHaveText(icelandicHeading) + } await expect(page).toHaveURL('/en') }) test('should toggle mega-menu @lang:is', async () => { - const page = await context.newPage() - await page.goto('/') + const page = await createPageAndNavigate(context, '/') await page .locator('[data-testid="frontpage-burger-button"]:nth-child(2)') .click() await expect( - page.locator('[data-testid="mega-menu-link"] > a'), - ).toHaveCountGreaterThan(18) + page.locator('[data-testid="mega-menu-link"] > a').count(), + ).resolves.toBeGreaterThan(18) }) test('burger menu should open and close', async () => { - // Arrange - const page = await context.newPage() - page.goto('/') + const page = await createPageAndNavigate(context, '/') await page.getByRole('button', { name: 'Valmynd' }).click() - // Act await expect(page.getByRole('dialog', { name: 'Menu' })).toBeVisible() await expect( page.getByRole('paragraph').filter({ hasText: 'Þjónustuflokkar' }), diff --git a/apps/web/e2e/smoke/search.spec.ts b/apps/web/e2e/smoke/search.spec.ts index c0bffb617641..59ac59f09d03 100644 --- a/apps/web/e2e/smoke/search.spec.ts +++ b/apps/web/e2e/smoke/search.spec.ts @@ -29,10 +29,10 @@ test.describe('Search feature', () => { await page.goto('/') await page .getByRole('textbox', { name: 'Leitaðu á Ísland.is' }) - .type(testPhrase, { delay: 100 }) + .fill(testPhrase) await page.keyboard.press('Enter') const testResults = page.locator('[data-testid="search-result"]') - await expect(testResults).toHaveCountGreaterThan(9) + await expect(testResults.count()).resolves.toBeGreaterThan(9) const searchUrl = page.url() await testResults.nth(0).click() await page.waitForLoadState('networkidle') @@ -42,17 +42,16 @@ test.describe('Search feature', () => { test('should have no search results for long bogus search words', async () => { const page = await context.newPage() await page.goto('/') - await page.type( - 'role=textbox[name="Leitaðu á Ísland.is"]', - 'abcdefhijklmnopqrstuvwxyz1234567890', - ) + await page + .getByRole('textbox', { name: 'Leitaðu á Ísland.is' }) + .fill('abcdefhijklmnopqrstuvwxyz1234567890') await page.keyboard.press('Enter') await page.waitForLoadState('networkidle') const testResults = page.locator('[data-testid="search-result"]') await expect(testResults).toHaveCount(0) }) - test.skip('should search in Enlish', async () => { + test.skip('should search in English', async () => { return }) }) diff --git a/apps/web/e2e/smoke/sites-of-institutions.spec.ts b/apps/web/e2e/smoke/sites-of-institutions.spec.ts index 88e33e925564..5bac4e00b321 100644 --- a/apps/web/e2e/smoke/sites-of-institutions.spec.ts +++ b/apps/web/e2e/smoke/sites-of-institutions.spec.ts @@ -6,13 +6,11 @@ import { Page, session, test, - urls, } from '@island.is/testing/e2e' type GetByRole = Pick['getByRole'] type GetByRoleParameters = Parameters -test.use({ baseURL: urls.islandisBaseUrl }) type Orgs = { organisationName: string organisationHome?: string @@ -45,6 +43,7 @@ const orgs: Orgs[] = [ test.describe('Sites of institutions', () => { let context: BrowserContext + test.beforeAll(async ({ browser }) => { context = await session({ browser, @@ -52,29 +51,37 @@ test.describe('Sites of institutions', () => { homeUrl: '/s', }) }) + test.afterAll(async () => { await context.close() }) + for (const { organisationName, organisationHome = `/${slugify(organisationName, { lower: true })}`, target, enabled, } of orgs) { - test(organisationName, async () => { + test(organisationName, async ({ browser }) => { if (enabled) return - const page = await context.newPage() + const pageContext = await session({ + browser, + idsLoginOn: false, + homeUrl: '/s', + }) + const page = await pageContext.newPage() const url = `/s${organisationHome}` await page.goto(url) await expect( page .getByRole(target?.role ?? 'heading', { - ...{ name: organisationName }, + name: organisationName, ...target?.options, }) .first(), ).toBeVisible() await page.close() + await pageContext.close() }) } }) diff --git a/apps/web/jest.config.ts b/apps/web/jest.config.ts index 741ea049992a..b853eafe543f 100644 --- a/apps/web/jest.config.ts +++ b/apps/web/jest.config.ts @@ -13,4 +13,5 @@ export default { moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], coverageDirectory: '/coverage/apps/web', displayName: 'web', + testPathIgnorePatterns: ['/apps/web/e2e'], } diff --git a/apps/web/playwright.config.ts b/apps/web/playwright.config.ts index 435dc6f9a54d..171cc5502dd2 100644 --- a/apps/web/playwright.config.ts +++ b/apps/web/playwright.config.ts @@ -4,7 +4,7 @@ import './e2e/utils/addons' const webConfig = createPlaywrightConfig({ webServerUrl: 'http://localhost:4200', - command: 'yarn dev-init web && source .env.secret && yarn dev web', + command: '(yarn dev-init web && yarn dev web)', cwd: '../../', }) diff --git a/libs/testing/e2e/src/lib/helpers/api-tools.ts b/libs/testing/e2e/src/lib/helpers/api-tools.ts index 09e4042c1b3f..a4fd275f2143 100644 --- a/libs/testing/e2e/src/lib/helpers/api-tools.ts +++ b/libs/testing/e2e/src/lib/helpers/api-tools.ts @@ -1,4 +1,4 @@ -import { Page } from '@playwright/test' +import { Page, BrowserContext } from '@playwright/test' /** * Waits for a network request to complete and verifies its operation name. @@ -21,3 +21,19 @@ export const verifyRequestCompletion = async ( return await response.json() } + +/** + * Creates a new page in the given browser context and navigates to the specified URL. + * + * @param context - The browser context in which to create the new page. + * @param url - The URL to navigate to. + * @returns A promise that resolves to the created page. + */ +export const createPageAndNavigate = async ( + context: BrowserContext, + url: string, +) => { + const page = await context.newPage() + await page.goto(url) + return page +} From af54dcc5a7e312e8c86abbc9a1b4eb12fc055149 Mon Sep 17 00:00:00 2001 From: Svana Date: Fri, 15 Nov 2024 12:30:12 +0000 Subject: [PATCH 03/18] Minor tweaks --- apps/web/e2e/smoke/homepage.spec.ts | 2 +- apps/web/e2e/smoke/search.spec.ts | 2 +- .../e2e/smoke/sites-of-institutions.spec.ts | 4 +- apps/web/e2e/utils/addons.ts | 40 ------------------- apps/web/playwright.config.ts | 2 - libs/testing/e2e/src/index.ts | 3 +- 6 files changed, 6 insertions(+), 47 deletions(-) delete mode 100644 apps/web/e2e/utils/addons.ts diff --git a/apps/web/e2e/smoke/homepage.spec.ts b/apps/web/e2e/smoke/homepage.spec.ts index ca1f5d6da928..93367e15048b 100644 --- a/apps/web/e2e/smoke/homepage.spec.ts +++ b/apps/web/e2e/smoke/homepage.spec.ts @@ -1,5 +1,5 @@ import { - BrowserContext, + type BrowserContext, createPageAndNavigate, expect, session, diff --git a/apps/web/e2e/smoke/search.spec.ts b/apps/web/e2e/smoke/search.spec.ts index 59ac59f09d03..d1a38872936a 100644 --- a/apps/web/e2e/smoke/search.spec.ts +++ b/apps/web/e2e/smoke/search.spec.ts @@ -1,5 +1,5 @@ import { - BrowserContext, + type BrowserContext, expect, session, test, diff --git a/apps/web/e2e/smoke/sites-of-institutions.spec.ts b/apps/web/e2e/smoke/sites-of-institutions.spec.ts index 5bac4e00b321..71aa1a2e411a 100644 --- a/apps/web/e2e/smoke/sites-of-institutions.spec.ts +++ b/apps/web/e2e/smoke/sites-of-institutions.spec.ts @@ -1,9 +1,9 @@ import slugify from 'slugify' import { - BrowserContext, + type BrowserContext, expect, - Page, + type Page, session, test, } from '@island.is/testing/e2e' diff --git a/apps/web/e2e/utils/addons.ts b/apps/web/e2e/utils/addons.ts deleted file mode 100644 index e012fa9e99ac..000000000000 --- a/apps/web/e2e/utils/addons.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { expect, Locator, Page, sleep } from '@island.is/testing/e2e' - -expect.extend({ - async toHaveCountGreaterThan( - received: Locator, - value: number, - options: { timeout: number; sleepTime: number } = { - timeout: 10000, - sleepTime: 100, - }, - ) { - const initialTime = Date.now() - let count = -1 - while (count <= value) { - count = await received.count() - if (Date.now() > initialTime + options.timeout) - return { message: () => 'Timeout', pass: false } - await sleep(options.sleepTime) - } - return { - message: () => `Found ${count} elements`, - pass: true, - } - }, - async toBeApplication(received: string | Page, applicationType = '\\w+') { - const url: string = typeof received == 'string' ? received : received.url() - const protocol = 'https?://' - const host = '[^/]+' - const applicationId = '(/(\\w|-)*)?' - const applicationRegExp = new RegExp( - `^${protocol}${host}/umsoknir/${applicationType}${applicationId}$`, - ) - const pass = applicationRegExp.test(url) - const message = () => - `Current page is ${pass ? '' : '*not* '}an application - Pattern ${applicationRegExp} - URL is ${url}` - return { message, pass } - }, -}) diff --git a/apps/web/playwright.config.ts b/apps/web/playwright.config.ts index 171cc5502dd2..f08f9fb5b6b0 100644 --- a/apps/web/playwright.config.ts +++ b/apps/web/playwright.config.ts @@ -1,7 +1,5 @@ import { createPlaywrightConfig } from '@island.is/testing/e2e' -import './e2e/utils/addons' - const webConfig = createPlaywrightConfig({ webServerUrl: 'http://localhost:4200', command: '(yarn dev-init web && yarn dev web)', diff --git a/libs/testing/e2e/src/index.ts b/libs/testing/e2e/src/index.ts index 1e4c8baa004e..f7fba34a0d79 100644 --- a/libs/testing/e2e/src/index.ts +++ b/libs/testing/e2e/src/index.ts @@ -9,4 +9,5 @@ export * from './lib/session/session' export * from './lib/modules/urls' export * from './lib/helpers/utils' export * from './lib/config/playwright-config' -export { test, expect, Page, Locator, BrowserContext } from '@playwright/test' +export { test, expect } from '@playwright/test' +export type { Page, Locator, BrowserContext } from '@playwright/test' From 12267594bb9d92e0e4c9656e9b83bc505fecc99b Mon Sep 17 00:00:00 2001 From: Svana Date: Fri, 15 Nov 2024 14:01:15 +0000 Subject: [PATCH 04/18] Small test improvements --- apps/web/e2e/smoke/homepage.spec.ts | 13 ---- apps/web/e2e/smoke/search.spec.ts | 4 +- .../e2e/smoke/sites-of-institutions.spec.ts | 62 +++++++++---------- 3 files changed, 33 insertions(+), 46 deletions(-) diff --git a/apps/web/e2e/smoke/homepage.spec.ts b/apps/web/e2e/smoke/homepage.spec.ts index 93367e15048b..8da952eab761 100644 --- a/apps/web/e2e/smoke/homepage.spec.ts +++ b/apps/web/e2e/smoke/homepage.spec.ts @@ -77,9 +77,6 @@ test.describe('Front page', () => { }) test(`should navigate to featured link @lang:is`, async () => { - if (!context) { - throw new Error('Context is not initialized') - } test.slow() const page = await createPageAndNavigate(context, '/') const featuredLinks = page.locator('[data-testid="featured-link"]') @@ -104,9 +101,6 @@ test.describe('Front page', () => { }) test(`should navigate to featured link @lang:en`, async () => { - if (!context) { - throw new Error('Context is not initialized') - } test.slow() const page = await createPageAndNavigate(context, '/en') const featuredLinks = page.locator('[data-testid="featured-link"]') @@ -131,9 +125,6 @@ test.describe('Front page', () => { }) test(`should have link on life events pages to navigate back to the main page @lang:is`, async () => { - if (!context) { - throw new Error('Context is not initialized') - } test.slow() const page = await createPageAndNavigate(context, '/') const lifeEventsCards = page.locator('[data-testid="lifeevent-card"]') @@ -147,7 +138,6 @@ test.describe('Front page', () => { await lifeEventPage.goto(url) await lifeEventPage.locator('[data-testid="link-back-home"]').click() } - await lifeEventPage.locator('[data-testid="link-back-home"]').click() await expect( lifeEventPage.locator('data-testid=home-heading'), ).toBeVisible() @@ -157,9 +147,6 @@ test.describe('Front page', () => { }) test(`should have link on life events pages to navigate back to the main page @lang:en`, async () => { - if (!context) { - throw new Error('Context is not initialized') - } test.slow() const page = await createPageAndNavigate(context, '/en') const lifeEventsCards = page.locator('[data-testid="lifeevent-card"]') diff --git a/apps/web/e2e/smoke/search.spec.ts b/apps/web/e2e/smoke/search.spec.ts index d1a38872936a..ef4369bb3ae5 100644 --- a/apps/web/e2e/smoke/search.spec.ts +++ b/apps/web/e2e/smoke/search.spec.ts @@ -26,7 +26,7 @@ test.describe('Search feature', () => { test('has expected sections', async () => { const testPhrase = 'umsókn' const page = await context.newPage() - await page.goto('/') + await page.goto('/', { waitUntil: 'networkidle' }) await page .getByRole('textbox', { name: 'Leitaðu á Ísland.is' }) .fill(testPhrase) @@ -41,7 +41,7 @@ test.describe('Search feature', () => { test('should have no search results for long bogus search words', async () => { const page = await context.newPage() - await page.goto('/') + await page.goto('/', { waitUntil: 'networkidle' }) await page .getByRole('textbox', { name: 'Leitaðu á Ísland.is' }) .fill('abcdefhijklmnopqrstuvwxyz1234567890') diff --git a/apps/web/e2e/smoke/sites-of-institutions.spec.ts b/apps/web/e2e/smoke/sites-of-institutions.spec.ts index 71aa1a2e411a..7d9d5881a9a1 100644 --- a/apps/web/e2e/smoke/sites-of-institutions.spec.ts +++ b/apps/web/e2e/smoke/sites-of-institutions.spec.ts @@ -14,7 +14,7 @@ type GetByRoleParameters = Parameters type Orgs = { organisationName: string organisationHome?: string - enabled?: boolean + skip?: boolean target?: { role: GetByRoleParameters[0]; options?: GetByRoleParameters[1] } } const orgs: Orgs[] = [ @@ -27,7 +27,7 @@ const orgs: Orgs[] = [ { organisationName: 'Sjúkratryggingar', target: { role: 'link' } }, { organisationName: 'Ríkislögmaður' }, { organisationName: 'Landskjörstjórn', target: { role: 'link' } }, - { organisationName: 'Opinber nýsköpun', enabled: true }, + { organisationName: 'Opinber nýsköpun', skip: true }, { organisationName: 'Sýslumenn' }, { organisationName: 'Fjársýslan' }, { @@ -43,7 +43,6 @@ const orgs: Orgs[] = [ test.describe('Sites of institutions', () => { let context: BrowserContext - test.beforeAll(async ({ browser }) => { context = await session({ browser, @@ -51,37 +50,38 @@ test.describe('Sites of institutions', () => { homeUrl: '/s', }) }) - test.afterAll(async () => { await context.close() }) + orgs.forEach( + ({ + organisationName, + organisationHome = `/${slugify(organisationName, { lower: true })}`, + target, + skip, + }) => { + test(organisationName, async () => { + if (skip) return + const page = await context.newPage() + const url = `/s${organisationHome}` + + const response = await page.goto(url, { timeout: 30000 }) + expect(response?.ok()).toBe(true) - for (const { - organisationName, - organisationHome = `/${slugify(organisationName, { lower: true })}`, - target, - enabled, - } of orgs) { - test(organisationName, async ({ browser }) => { - if (enabled) return - const pageContext = await session({ - browser, - idsLoginOn: false, - homeUrl: '/s', + // Verify we landed on the correct URL + expect(page.url()).toContain(url) + + await expect( + page + .getByRole(target?.role ?? 'heading', { + ...{ name: organisationName }, + ...target?.options, + }) + .first(), + ).toBeVisible() + + await page.close() }) - const page = await pageContext.newPage() - const url = `/s${organisationHome}` - await page.goto(url) - await expect( - page - .getByRole(target?.role ?? 'heading', { - name: organisationName, - ...target?.options, - }) - .first(), - ).toBeVisible() - await page.close() - await pageContext.close() - }) - } + }, + ) }) From dc24b292630ba5bd0de10a6b256134592ca20f7a Mon Sep 17 00:00:00 2001 From: Svana Date: Fri, 15 Nov 2024 16:18:40 +0000 Subject: [PATCH 05/18] Docs update for web --- apps/web/README.md | 43 +++++++++++++++++++++++++++++------ apps/web/playwright.config.ts | 4 ++-- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/apps/web/README.md b/apps/web/README.md index 31eec864aecc..5802503bf2a4 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -90,18 +90,47 @@ yarn nx extract-strings web Currently, in this project, only the `Custom Page` content type utilizes the `Translation Namespace` content type for translations -### Starting e2e tests locally +### Further Documentation -You can start the e2e tests by running: +[Subpages](./docs/subpages.md) - Information on Layouts and Components used when +creating subpages for the web. -```bash -yarn e2e web +## E2E Testing + +### Quick Start + +To run the E2E tests for the `web` app: + +1. **Install dependencies** (if not already installed): + + ```bash + yarn install && yarn playwright install + ``` + +2. **Run the tests**: + + ```bash + yarn e2e web + ``` + +### Folder Structure + +The `e2e` directory is organized as follows: + +```shell +web/ +└── e2e/ + ├── smoke/ # Smoke tests for basic functionality + └── acceptance/ # Acceptance tests for detailed workflows ``` -## Further Documentation +### Mocking with Mockoon -[Subpages](./docs/subpages.md) - Information on Layouts and Components used when -creating subpages for the web. +Mock responses can be set up using Mockoon to simulate API behavior. Refer to the [Mockoon Usage Guide](../../libs/testing/e2e/README.md) for detailed instructions. + +### More Resources + +Refer to the [E2E Testing Library README](../../libs/testing/e2e/README.md) for common helper functions and utilities. ## Code owners and maintainers diff --git a/apps/web/playwright.config.ts b/apps/web/playwright.config.ts index f08f9fb5b6b0..06bd1a597476 100644 --- a/apps/web/playwright.config.ts +++ b/apps/web/playwright.config.ts @@ -1,9 +1,9 @@ import { createPlaywrightConfig } from '@island.is/testing/e2e' -const webConfig = createPlaywrightConfig({ +const playwrightConfig = createPlaywrightConfig({ webServerUrl: 'http://localhost:4200', command: '(yarn dev-init web && yarn dev web)', cwd: '../../', }) -export default webConfig +export default playwrightConfig From c3f0dbf3809797555e9422aea9e47247f97c2e01 Mon Sep 17 00:00:00 2001 From: Svana Date: Fri, 15 Nov 2024 16:19:49 +0000 Subject: [PATCH 06/18] Minor tweak --- apps/web/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/web/README.md b/apps/web/README.md index 5802503bf2a4..25f4fc9a9c74 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -90,11 +90,6 @@ yarn nx extract-strings web Currently, in this project, only the `Custom Page` content type utilizes the `Translation Namespace` content type for translations -### Further Documentation - -[Subpages](./docs/subpages.md) - Information on Layouts and Components used when -creating subpages for the web. - ## E2E Testing ### Quick Start @@ -132,6 +127,11 @@ Mock responses can be set up using Mockoon to simulate API behavior. Refer to th Refer to the [E2E Testing Library README](../../libs/testing/e2e/README.md) for common helper functions and utilities. +## Further Documentation + +[Subpages](./docs/subpages.md) - Information on Layouts and Components used when +creating subpages for the web. + ## Code owners and maintainers - [Stefna](https://github.com/orgs/island-is/teams/stefna/members) From 3e2cbf369c64bbc0e46a4e056094d21b41a75ef8 Mon Sep 17 00:00:00 2001 From: Svana Date: Mon, 18 Nov 2024 12:25:25 +0000 Subject: [PATCH 07/18] Workflow test --- .github/workflows/pullrequest.yml | 63 ++++++++++++++++++++++++++++--- apps/web/server.ts | 1 + 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 51e54f62e853..712fe9b8fcb8 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -34,7 +34,9 @@ jobs: outputs: TEST_CHUNKS: ${{ steps.test_projects.outputs.CHUNKS }} + E2E_CI_CHUNKS: ${{ steps.e2e_ci_projects.outputs.CHUNKS }} E2E_CHUNKS: ${{ steps.e2e_projects.outputs.CHUNKS }} + E2E_CI_BUILD_ID: ${{ steps.e2e_ci_projects.outputs.BUILD_ID }} E2E_BUILD_ID: ${{ steps.e2e_projects.outputs.BUILD_ID }} LINT_CHUNKS: ${{ steps.lint_projects.outputs.CHUNKS }} BUILD_CHUNKS: ${{ steps.build_projects.outputs.CHUNKS }} @@ -141,13 +143,25 @@ jobs: echo "CHUNKS={\"projects\":$CHUNKS}" >> "$GITHUB_OUTPUT" fi + - name: Prepare e2e-ci targets + id: e2e_ci_projects + env: + CHUNK_SIZE: 1 + run: | + set -euo pipefail + CHUNKS="$(./scripts/ci/generate-chunks.sh e2e-ci)" + if [[ "$CHUNKS" != "[]" ]]; then + echo "CHUNKS={\"projects\":$CHUNKS}" >> "$GITHUB_OUTPUT" + fi + echo BUILD_ID="$GITHUB_RUN_ID-$GITHUB_RUN_NUMBER-$(uuidgen)" >> "$GITHUB_OUTPUT" + - name: Prepare e2e targets id: e2e_projects env: CHUNK_SIZE: 1 run: | set -euo pipefail - CHUNKS="$(./scripts/ci/generate-chunks.sh e2e-ci)" + CHUNKS="$(./scripts/ci/generate-chunks.sh e2e)" if [[ "$CHUNKS" != "[]" ]]; then echo "CHUNKS={\"projects\":$CHUNKS}" >> "$GITHUB_OUTPUT" fi @@ -213,10 +227,10 @@ jobs: aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} docker-registry: 821090935708.dkr.ecr.eu-west-1.amazonaws.com/ - e2e: + e2e-ci: needs: - prepare - if: needs.prepare.outputs.E2E_CHUNKS + if: needs.prepare.outputs.E2E_CI_CHUNKS runs-on: ec2-runners container: image: public.ecr.aws/m3u4c4h9/island-is/actions-runner-public:latest @@ -227,10 +241,10 @@ jobs: CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} API_MOCKS: 'true' NODE_OPTIONS: --max-old-space-size=4096 - E2E_BUILD_ID: '${{ needs.prepare.outputs.E2E_BUILD_ID }}-${{ github.run_attempt }}' + E2E_CI_BUILD_ID: '${{ needs.prepare.outputs.E2E_CI_BUILD_ID }}-${{ github.run_attempt }}' strategy: fail-fast: false - matrix: ${{ fromJson(needs.prepare.outputs.E2E_CHUNKS) }} + matrix: ${{ fromJson(needs.prepare.outputs.E2E_CI_CHUNKS) }} steps: - uses: actions/checkout@v4 @@ -252,6 +266,42 @@ jobs: - name: Running e2e tests run: ./scripts/ci/40_e2e.sh "${AFFECTED_PROJECT}" + e2e: + needs: + - prepare + if: needs.prepare.outputs.E2E_CHUNKS + runs-on: ec2-runners + container: + image: public.ecr.aws/m3u4c4h9/island-is/actions-runner-public:latest + timeout-minutes: 35 + env: + AFFECTED_PROJECT: ${{ matrix.projects }} + NODE_OPTIONS: --max-old-space-size=4096 + E2E_BUILD_ID: '${{ needs.prepare.outputs.E2E_BUILD_ID }}-${{ github.run_attempt }}' + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.prepare.outputs.E2E_CHUNKS) }} + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version-file: 'package.json' + + - name: Setup yarn + run: corepack enable + + - name: Get cache + id: get-cache + uses: ./.github/actions/get-cache + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + keys: ${{ needs.prepare.outputs.CACHE_KEYS }} + enable-cache: 'node_modules,generated-files' + + - name: Running e2e tests + run: yarn e2e "${AFFECTED_PROJECT}" + linting-workspace: needs: - prepare @@ -410,6 +460,7 @@ jobs: - linting - run-shellcheck - formatting + - e2e-ci - e2e - build steps: @@ -417,6 +468,8 @@ jobs: run: '[[ ${{ needs.prepare.result }} == "success" ]] || exit 1' - name: Check tests success run: '[[ ${{ needs.tests.result }} != "failure" ]] || exit 1' + - name: Check e2e-ci success + run: '[[ ${{ needs.e2e-ci.result }} != "failure" ]] || exit 1' - name: Check e2e success run: '[[ ${{ needs.e2e.result }} != "failure" ]] || exit 1' - name: Check linting success diff --git a/apps/web/server.ts b/apps/web/server.ts index 6c816d3400d6..80bb8d187ca9 100644 --- a/apps/web/server.ts +++ b/apps/web/server.ts @@ -2,6 +2,7 @@ import { bootstrap } from '@island.is/infra-next-server' import proxyConfig from './proxy.config.json' +// test bootstrap({ name: 'web', appDir: 'apps/web', From 0d9addf1adc72ccbb915a26de78f137e9047863b Mon Sep 17 00:00:00 2001 From: Svana Date: Mon, 18 Nov 2024 13:59:08 +0000 Subject: [PATCH 08/18] Change web start command e2e playwright --- apps/web/playwright.config.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/web/playwright.config.ts b/apps/web/playwright.config.ts index 06bd1a597476..59f0f40d189b 100644 --- a/apps/web/playwright.config.ts +++ b/apps/web/playwright.config.ts @@ -2,7 +2,8 @@ import { createPlaywrightConfig } from '@island.is/testing/e2e' const playwrightConfig = createPlaywrightConfig({ webServerUrl: 'http://localhost:4200', - command: '(yarn dev-init web && yarn dev web)', + command: + '(cd infra && yarn cli run-local-env web --dependencies api --print --no-secrets --proxies)', cwd: '../../', }) From 394c8532fedac5bf3444f572db13ca49e63d278d Mon Sep 17 00:00:00 2001 From: Svana Date: Wed, 20 Nov 2024 16:06:53 +0000 Subject: [PATCH 09/18] Remove Playwright projects and add Tags --- apps/web/README.md | 17 ++++++++++------- apps/web/e2e/{smoke => }/homepage.spec.ts | 2 +- apps/web/e2e/{smoke => }/search.spec.ts | 2 +- .../{smoke => }/sites-of-institutions.spec.ts | 2 +- apps/web/playwright.config.ts | 3 +-- 5 files changed, 14 insertions(+), 12 deletions(-) rename apps/web/e2e/{smoke => }/homepage.spec.ts (99%) rename apps/web/e2e/{smoke => }/search.spec.ts (96%) rename apps/web/e2e/{smoke => }/sites-of-institutions.spec.ts (97%) diff --git a/apps/web/README.md b/apps/web/README.md index 25f4fc9a9c74..64f4f3ee6b0b 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -108,15 +108,18 @@ To run the E2E tests for the `web` app: yarn e2e web ``` -### Folder Structure +### Test Organization -The `e2e` directory is organized as follows: +The E2E tests for the `web` app are located in the `e2e` folder. -```shell -web/ -└── e2e/ - ├── smoke/ # Smoke tests for basic functionality - └── acceptance/ # Acceptance tests for detailed workflows +Tests are tagged based on their execution time or other criteria. Use `@fast` for quick tests and `@slow` for longer-running tests. Example: + +```typescript +import { test, expect } from '@playwright/test' + +test('should get paid', { tag: '@slow' }, () => { + // ... +}) ``` ### Mocking with Mockoon diff --git a/apps/web/e2e/smoke/homepage.spec.ts b/apps/web/e2e/homepage.spec.ts similarity index 99% rename from apps/web/e2e/smoke/homepage.spec.ts rename to apps/web/e2e/homepage.spec.ts index 8da952eab761..721cc2c3eb62 100644 --- a/apps/web/e2e/smoke/homepage.spec.ts +++ b/apps/web/e2e/homepage.spec.ts @@ -9,7 +9,7 @@ import { test.use({ baseURL: urls.islandisBaseUrl }) -test.describe('Front page', () => { +test.describe('Front page', { tag: '@fast' }, () => { let context: BrowserContext test.beforeAll(async ({ browser }) => { diff --git a/apps/web/e2e/smoke/search.spec.ts b/apps/web/e2e/search.spec.ts similarity index 96% rename from apps/web/e2e/smoke/search.spec.ts rename to apps/web/e2e/search.spec.ts index ef4369bb3ae5..ada43dd7989a 100644 --- a/apps/web/e2e/smoke/search.spec.ts +++ b/apps/web/e2e/search.spec.ts @@ -8,7 +8,7 @@ import { test.use({ baseURL: urls.islandisBaseUrl }) -test.describe('Search feature', () => { +test.describe('Search feature', { tag: '@fast' }, () => { let context: BrowserContext test.beforeAll(async ({ browser }) => { context = await session({ diff --git a/apps/web/e2e/smoke/sites-of-institutions.spec.ts b/apps/web/e2e/sites-of-institutions.spec.ts similarity index 97% rename from apps/web/e2e/smoke/sites-of-institutions.spec.ts rename to apps/web/e2e/sites-of-institutions.spec.ts index 7d9d5881a9a1..1d287c498f8d 100644 --- a/apps/web/e2e/smoke/sites-of-institutions.spec.ts +++ b/apps/web/e2e/sites-of-institutions.spec.ts @@ -41,7 +41,7 @@ const orgs: Orgs[] = [ { organisationName: 'Útlendingastofnun', target: { role: 'link' } }, ] -test.describe('Sites of institutions', () => { +test.describe('Sites of institutions', { tag: '@fast' }, () => { let context: BrowserContext test.beforeAll(async ({ browser }) => { context = await session({ diff --git a/apps/web/playwright.config.ts b/apps/web/playwright.config.ts index 59f0f40d189b..e5420a14fe04 100644 --- a/apps/web/playwright.config.ts +++ b/apps/web/playwright.config.ts @@ -3,8 +3,7 @@ import { createPlaywrightConfig } from '@island.is/testing/e2e' const playwrightConfig = createPlaywrightConfig({ webServerUrl: 'http://localhost:4200', command: - '(cd infra && yarn cli run-local-env web --dependencies api --print --no-secrets --proxies)', - cwd: '../../', + '(yarn infra run-local-env web --dependencies api --print --no-secrets --proxies)', }) export default playwrightConfig From b9461390471d82ea04510739a81344f8dd71d26a Mon Sep 17 00:00:00 2001 From: Svana Date: Wed, 20 Nov 2024 16:26:33 +0000 Subject: [PATCH 10/18] Revert workflow test --- .github/workflows/pullrequest.yml | 63 +++---------------------------- apps/web/README.md | 4 -- apps/web/playwright.config.ts | 2 +- apps/web/server.ts | 1 - 4 files changed, 6 insertions(+), 64 deletions(-) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 712fe9b8fcb8..51e54f62e853 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -34,9 +34,7 @@ jobs: outputs: TEST_CHUNKS: ${{ steps.test_projects.outputs.CHUNKS }} - E2E_CI_CHUNKS: ${{ steps.e2e_ci_projects.outputs.CHUNKS }} E2E_CHUNKS: ${{ steps.e2e_projects.outputs.CHUNKS }} - E2E_CI_BUILD_ID: ${{ steps.e2e_ci_projects.outputs.BUILD_ID }} E2E_BUILD_ID: ${{ steps.e2e_projects.outputs.BUILD_ID }} LINT_CHUNKS: ${{ steps.lint_projects.outputs.CHUNKS }} BUILD_CHUNKS: ${{ steps.build_projects.outputs.CHUNKS }} @@ -143,25 +141,13 @@ jobs: echo "CHUNKS={\"projects\":$CHUNKS}" >> "$GITHUB_OUTPUT" fi - - name: Prepare e2e-ci targets - id: e2e_ci_projects - env: - CHUNK_SIZE: 1 - run: | - set -euo pipefail - CHUNKS="$(./scripts/ci/generate-chunks.sh e2e-ci)" - if [[ "$CHUNKS" != "[]" ]]; then - echo "CHUNKS={\"projects\":$CHUNKS}" >> "$GITHUB_OUTPUT" - fi - echo BUILD_ID="$GITHUB_RUN_ID-$GITHUB_RUN_NUMBER-$(uuidgen)" >> "$GITHUB_OUTPUT" - - name: Prepare e2e targets id: e2e_projects env: CHUNK_SIZE: 1 run: | set -euo pipefail - CHUNKS="$(./scripts/ci/generate-chunks.sh e2e)" + CHUNKS="$(./scripts/ci/generate-chunks.sh e2e-ci)" if [[ "$CHUNKS" != "[]" ]]; then echo "CHUNKS={\"projects\":$CHUNKS}" >> "$GITHUB_OUTPUT" fi @@ -227,10 +213,10 @@ jobs: aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} docker-registry: 821090935708.dkr.ecr.eu-west-1.amazonaws.com/ - e2e-ci: + e2e: needs: - prepare - if: needs.prepare.outputs.E2E_CI_CHUNKS + if: needs.prepare.outputs.E2E_CHUNKS runs-on: ec2-runners container: image: public.ecr.aws/m3u4c4h9/island-is/actions-runner-public:latest @@ -241,42 +227,6 @@ jobs: CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} API_MOCKS: 'true' NODE_OPTIONS: --max-old-space-size=4096 - E2E_CI_BUILD_ID: '${{ needs.prepare.outputs.E2E_CI_BUILD_ID }}-${{ github.run_attempt }}' - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.prepare.outputs.E2E_CI_CHUNKS) }} - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version-file: 'package.json' - - - name: Setup yarn - run: corepack enable - - - name: Get cache - id: get-cache - uses: ./.github/actions/get-cache - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - keys: ${{ needs.prepare.outputs.CACHE_KEYS }} - enable-cache: 'node_modules,cypress,generated-files' - - - name: Running e2e tests - run: ./scripts/ci/40_e2e.sh "${AFFECTED_PROJECT}" - - e2e: - needs: - - prepare - if: needs.prepare.outputs.E2E_CHUNKS - runs-on: ec2-runners - container: - image: public.ecr.aws/m3u4c4h9/island-is/actions-runner-public:latest - timeout-minutes: 35 - env: - AFFECTED_PROJECT: ${{ matrix.projects }} - NODE_OPTIONS: --max-old-space-size=4096 E2E_BUILD_ID: '${{ needs.prepare.outputs.E2E_BUILD_ID }}-${{ github.run_attempt }}' strategy: fail-fast: false @@ -297,10 +247,10 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} keys: ${{ needs.prepare.outputs.CACHE_KEYS }} - enable-cache: 'node_modules,generated-files' + enable-cache: 'node_modules,cypress,generated-files' - name: Running e2e tests - run: yarn e2e "${AFFECTED_PROJECT}" + run: ./scripts/ci/40_e2e.sh "${AFFECTED_PROJECT}" linting-workspace: needs: @@ -460,7 +410,6 @@ jobs: - linting - run-shellcheck - formatting - - e2e-ci - e2e - build steps: @@ -468,8 +417,6 @@ jobs: run: '[[ ${{ needs.prepare.result }} == "success" ]] || exit 1' - name: Check tests success run: '[[ ${{ needs.tests.result }} != "failure" ]] || exit 1' - - name: Check e2e-ci success - run: '[[ ${{ needs.e2e-ci.result }} != "failure" ]] || exit 1' - name: Check e2e success run: '[[ ${{ needs.e2e.result }} != "failure" ]] || exit 1' - name: Check linting success diff --git a/apps/web/README.md b/apps/web/README.md index 64f4f3ee6b0b..b2706196b7a2 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -122,10 +122,6 @@ test('should get paid', { tag: '@slow' }, () => { }) ``` -### Mocking with Mockoon - -Mock responses can be set up using Mockoon to simulate API behavior. Refer to the [Mockoon Usage Guide](../../libs/testing/e2e/README.md) for detailed instructions. - ### More Resources Refer to the [E2E Testing Library README](../../libs/testing/e2e/README.md) for common helper functions and utilities. diff --git a/apps/web/playwright.config.ts b/apps/web/playwright.config.ts index e5420a14fe04..ed79a07fe22b 100644 --- a/apps/web/playwright.config.ts +++ b/apps/web/playwright.config.ts @@ -3,7 +3,7 @@ import { createPlaywrightConfig } from '@island.is/testing/e2e' const playwrightConfig = createPlaywrightConfig({ webServerUrl: 'http://localhost:4200', command: - '(yarn infra run-local-env web --dependencies api --print --no-secrets --proxies)', + 'yarn infra run-local-env web --dependencies api --print --no-secrets --proxies', }) export default playwrightConfig diff --git a/apps/web/server.ts b/apps/web/server.ts index 80bb8d187ca9..6c816d3400d6 100644 --- a/apps/web/server.ts +++ b/apps/web/server.ts @@ -2,7 +2,6 @@ import { bootstrap } from '@island.is/infra-next-server' import proxyConfig from './proxy.config.json' -// test bootstrap({ name: 'web', appDir: 'apps/web', From 0783e047c1eb2c0386302d95ef2da48040494844 Mon Sep 17 00:00:00 2001 From: Svana Date: Thu, 21 Nov 2024 10:18:49 +0000 Subject: [PATCH 11/18] Minor test updates --- apps/web/e2e/homepage.spec.ts | 46 ++++++++++++++++++----------------- apps/web/e2e/search.spec.ts | 2 +- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/apps/web/e2e/homepage.spec.ts b/apps/web/e2e/homepage.spec.ts index 721cc2c3eb62..9eb3c9e6afb5 100644 --- a/apps/web/e2e/homepage.spec.ts +++ b/apps/web/e2e/homepage.spec.ts @@ -47,11 +47,13 @@ test.describe('Front page', { tag: '@fast' }, () => { ) const lifeEventPage = await context.newPage() for (const url of lifeEventUrls) { - const result = await lifeEventPage.goto(url ?? '') - await expect( - lifeEventPage.getByRole('link', { name: 'island.is logo' }), - ).toBeVisible() - expect(result?.status()).toBe(200) + if (url) { + const result = await lifeEventPage.goto(url ?? '') + await expect( + lifeEventPage.getByRole('link', { name: 'island.is logo' }), + ).toBeVisible() + expect(result?.status()).toBe(200) + } } await lifeEventPage.close() }) @@ -67,11 +69,13 @@ test.describe('Front page', { tag: '@fast' }, () => { ) const lifeEventPage = await context.newPage() for (const url of lifeEventUrls) { - const result = await lifeEventPage.goto(url ?? '') - await expect( - lifeEventPage.getByRole('link', { name: 'island.is logo' }), - ).toBeVisible() - expect(result?.status()).toBe(200) + if (url) { + const result = await lifeEventPage.goto(url ?? '') + await expect( + lifeEventPage.getByRole('link', { name: 'island.is logo' }), + ).toBeVisible() + expect(result?.status()).toBe(200) + } } await lifeEventPage.close() }) @@ -137,11 +141,11 @@ test.describe('Front page', { tag: '@fast' }, () => { if (url) { await lifeEventPage.goto(url) await lifeEventPage.locator('[data-testid="link-back-home"]').click() + await expect( + lifeEventPage.locator('data-testid=home-heading'), + ).toBeVisible() + await expect(lifeEventPage).toHaveURL('/') } - await expect( - lifeEventPage.locator('data-testid=home-heading'), - ).toBeVisible() - await expect(lifeEventPage).toHaveURL('/') } await lifeEventPage.close() }) @@ -159,12 +163,12 @@ test.describe('Front page', { tag: '@fast' }, () => { if (url) { await lifeEventPage.goto(url) await lifeEventPage.locator('[data-testid="link-back-home"]').click() + await lifeEventPage.locator('[data-testid="link-back-home"]').click() + await expect( + lifeEventPage.locator('data-testid=home-heading'), + ).toBeVisible() + await expect(lifeEventPage).toHaveURL('/en') } - await lifeEventPage.locator('[data-testid="link-back-home"]').click() - await expect( - lifeEventPage.locator('data-testid=home-heading'), - ).toBeVisible() - await expect(lifeEventPage).toHaveURL('/en') } await lifeEventPage.close() }) @@ -195,9 +199,7 @@ test.describe('Front page', { tag: '@fast' }, () => { await page.getByRole('button', { name: 'Valmynd' }).click() await expect(page.getByRole('dialog', { name: 'Menu' })).toBeVisible() - await expect( - page.getByRole('paragraph').filter({ hasText: 'Þjónustuflokkar' }), - ).toBeVisible() + await expect(page.getByText('Þjónustuflokkar')).toBeVisible() await expect(page.getByRole('dialog', { name: 'Menu' })).toBeVisible() // Heading is "visible" behind menu // await expect(page.getByTestId('home-heading')).not.toBeVisible() diff --git a/apps/web/e2e/search.spec.ts b/apps/web/e2e/search.spec.ts index ada43dd7989a..f47e1d5f3c67 100644 --- a/apps/web/e2e/search.spec.ts +++ b/apps/web/e2e/search.spec.ts @@ -23,7 +23,7 @@ test.describe('Search feature', { tag: '@fast' }, () => { await context.close() }) - test('has expected sections', async () => { + test('should display search results and navigate to result page', async () => { const testPhrase = 'umsókn' const page = await context.newPage() await page.goto('/', { waitUntil: 'networkidle' }) From d2393a5daefb6dfb734e190bcc60a4568c460c41 Mon Sep 17 00:00:00 2001 From: Svana Date: Thu, 21 Nov 2024 11:02:55 +0000 Subject: [PATCH 12/18] Docs update for web --- apps/web/README.md | 30 ++++++------------------------ apps/web/jest.config.ts | 1 - jest.preset.js | 1 + 3 files changed, 7 insertions(+), 25 deletions(-) diff --git a/apps/web/README.md b/apps/web/README.md index b2706196b7a2..bb15186871f1 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -96,35 +96,17 @@ Currently, in this project, only the `Custom Page` content type utilizes the `Tr To run the E2E tests for the `web` app: -1. **Install dependencies** (if not already installed): - - ```bash - yarn install && yarn playwright install - ``` - -2. **Run the tests**: - - ```bash - yarn e2e web - ``` - -### Test Organization - -The E2E tests for the `web` app are located in the `e2e` folder. - -Tests are tagged based on their execution time or other criteria. Use `@fast` for quick tests and `@slow` for longer-running tests. Example: - -```typescript -import { test, expect } from '@playwright/test' +```bash +# Install dependencies +yarn install && yarn codegen -test('should get paid', { tag: '@slow' }, () => { - // ... -}) +# Start the server +yarn nx e2e web ``` ### More Resources -Refer to the [E2E Testing Library README](../../libs/testing/e2e/README.md) for common helper functions and utilities. +For further details, refer to the [E2E Testing Library README](../../libs/testing/e2e/README.md). ## Further Documentation diff --git a/apps/web/jest.config.ts b/apps/web/jest.config.ts index b853eafe543f..741ea049992a 100644 --- a/apps/web/jest.config.ts +++ b/apps/web/jest.config.ts @@ -13,5 +13,4 @@ export default { moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], coverageDirectory: '/coverage/apps/web', displayName: 'web', - testPathIgnorePatterns: ['/apps/web/e2e'], } diff --git a/jest.preset.js b/jest.preset.js index 1651c8322bda..38a1ff9c94bd 100644 --- a/jest.preset.js +++ b/jest.preset.js @@ -6,6 +6,7 @@ const customResolver = path.join(__dirname, 'jest.resolver.js') module.exports = { ...nxPresetRest, testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'], + testPathIgnorePatterns: ['/apps/**/e2e'], resolver: customResolver, moduleFileExtensions: ['ts', 'js', 'html'], coverageReporters: ['json'], From a35543c4141d83e6c028cdea6934e510da23c13b Mon Sep 17 00:00:00 2001 From: Svana Date: Thu, 21 Nov 2024 11:20:54 +0000 Subject: [PATCH 13/18] Test --- jest.preset.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jest.preset.js b/jest.preset.js index 38a1ff9c94bd..91dff7b208d1 100644 --- a/jest.preset.js +++ b/jest.preset.js @@ -6,7 +6,7 @@ const customResolver = path.join(__dirname, 'jest.resolver.js') module.exports = { ...nxPresetRest, testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'], - testPathIgnorePatterns: ['/apps/**/e2e'], + testPathIgnorePatterns: ['/apps/.*/e2e'], resolver: customResolver, moduleFileExtensions: ['ts', 'js', 'html'], coverageReporters: ['json'], From 92511345f804782cea3c0b092cfb46ce8236dcaf Mon Sep 17 00:00:00 2001 From: Svana Date: Thu, 21 Nov 2024 14:00:04 +0000 Subject: [PATCH 14/18] Make web proxy URL dynamic --- apps/web/infra/web.ts | 2 +- apps/web/proxy.config.json | 6 ------ apps/web/proxy.config.ts | 8 ++++++++ apps/web/server.ts | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) delete mode 100644 apps/web/proxy.config.json create mode 100644 apps/web/proxy.config.ts diff --git a/apps/web/infra/web.ts b/apps/web/infra/web.ts index a85284278d41..16c7c456e08f 100644 --- a/apps/web/infra/web.ts +++ b/apps/web/infra/web.ts @@ -7,7 +7,7 @@ export const serviceSetup = (services: { web .namespace('islandis') .env({ - API_URL: ref((h) => `http://${h.svc(services.api)}`), + GRAPHQL_API_URL: ref((h) => `http://${h.svc(services.api)}`), TRACKING_DOMAIN: { dev: 'beta.dev01.devland.is', staging: 'beta.staging01.devland.is', diff --git a/apps/web/proxy.config.json b/apps/web/proxy.config.json deleted file mode 100644 index 9824b19ff8a4..000000000000 --- a/apps/web/proxy.config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "/api": { - "target": "http://localhost:4444", - "secure": false - } -} diff --git a/apps/web/proxy.config.ts b/apps/web/proxy.config.ts new file mode 100644 index 000000000000..0b7677f0cdd6 --- /dev/null +++ b/apps/web/proxy.config.ts @@ -0,0 +1,8 @@ +const proxyConfig = { + '/api': { + target: process.env.GRAPHQL_API_URL ?? 'http://localhost:4444', + secure: false, + }, +} + +export default proxyConfig diff --git a/apps/web/server.ts b/apps/web/server.ts index 6c816d3400d6..2c086f325f42 100644 --- a/apps/web/server.ts +++ b/apps/web/server.ts @@ -1,6 +1,6 @@ import { bootstrap } from '@island.is/infra-next-server' -import proxyConfig from './proxy.config.json' +import proxyConfig from './proxy.config' bootstrap({ name: 'web', From 3e5405be1de458623b1b13d357b812ad271e7c97 Mon Sep 17 00:00:00 2001 From: andes-it Date: Thu, 21 Nov 2024 14:01:29 +0000 Subject: [PATCH 15/18] chore: charts update dirty files --- charts/islandis/values.dev.yaml | 2 +- charts/islandis/values.prod.yaml | 2 +- charts/islandis/values.staging.yaml | 2 +- charts/services/web/values.dev.yaml | 2 +- charts/services/web/values.prod.yaml | 2 +- charts/services/web/values.staging.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/charts/islandis/values.dev.yaml b/charts/islandis/values.dev.yaml index cf7b2fabaa49..8cbd2263e61b 100644 --- a/charts/islandis/values.dev.yaml +++ b/charts/islandis/values.dev.yaml @@ -3373,11 +3373,11 @@ user-notification-worker: web: enabled: true env: - API_URL: 'http://web-api' DISABLE_API_CATALOGUE: 'false' DISABLE_ORGANIZATION_CHATBOT: 'false' DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'dev' + GRAPHQL_API_URL: 'http://web-api' LOG_LEVEL: 'info' NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' diff --git a/charts/islandis/values.prod.yaml b/charts/islandis/values.prod.yaml index 66ded2ed398d..30d898f850d3 100644 --- a/charts/islandis/values.prod.yaml +++ b/charts/islandis/values.prod.yaml @@ -3249,11 +3249,11 @@ user-notification-worker: web: enabled: true env: - API_URL: 'http://web-api' DISABLE_API_CATALOGUE: 'false' DISABLE_ORGANIZATION_CHATBOT: 'false' DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'prod' + GRAPHQL_API_URL: 'http://web-api' LOG_LEVEL: 'info' NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' diff --git a/charts/islandis/values.staging.yaml b/charts/islandis/values.staging.yaml index f0836bbb7380..52305bf966cb 100644 --- a/charts/islandis/values.staging.yaml +++ b/charts/islandis/values.staging.yaml @@ -3111,11 +3111,11 @@ web: basicAuth: '/k8s/web/basic_auth' enabled: true env: - API_URL: 'http://web-api' DISABLE_API_CATALOGUE: 'false' DISABLE_ORGANIZATION_CHATBOT: 'false' DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'staging' + GRAPHQL_API_URL: 'http://web-api' LOG_LEVEL: 'info' NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' diff --git a/charts/services/web/values.dev.yaml b/charts/services/web/values.dev.yaml index a6455c2f5c34..8c070d97cb86 100644 --- a/charts/services/web/values.dev.yaml +++ b/charts/services/web/values.dev.yaml @@ -19,11 +19,11 @@ global: name: 'web' enabled: true env: - API_URL: 'http://web-api' DISABLE_API_CATALOGUE: 'false' DISABLE_ORGANIZATION_CHATBOT: 'false' DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'dev' + GRAPHQL_API_URL: 'http://web-api' LOG_LEVEL: 'info' NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' diff --git a/charts/services/web/values.prod.yaml b/charts/services/web/values.prod.yaml index a5c86c5c9db1..ad44e8e802a7 100644 --- a/charts/services/web/values.prod.yaml +++ b/charts/services/web/values.prod.yaml @@ -19,11 +19,11 @@ global: name: 'web' enabled: true env: - API_URL: 'http://web-api' DISABLE_API_CATALOGUE: 'false' DISABLE_ORGANIZATION_CHATBOT: 'false' DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'prod' + GRAPHQL_API_URL: 'http://web-api' LOG_LEVEL: 'info' NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' diff --git a/charts/services/web/values.staging.yaml b/charts/services/web/values.staging.yaml index 4a0b40a3fa19..a3f63a994525 100644 --- a/charts/services/web/values.staging.yaml +++ b/charts/services/web/values.staging.yaml @@ -20,11 +20,11 @@ name: 'web' basicAuth: '/k8s/web/basic_auth' enabled: true env: - API_URL: 'http://web-api' DISABLE_API_CATALOGUE: 'false' DISABLE_ORGANIZATION_CHATBOT: 'false' DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'staging' + GRAPHQL_API_URL: 'http://web-api' LOG_LEVEL: 'info' NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' From 14c8be2ae35f6912c683672c55c58145296d37ec Mon Sep 17 00:00:00 2001 From: Svana Date: Thu, 21 Nov 2024 14:30:40 +0000 Subject: [PATCH 16/18] Fix --- apps/web/infra/web.ts | 2 +- apps/web/proxy.config.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/infra/web.ts b/apps/web/infra/web.ts index 16c7c456e08f..a85284278d41 100644 --- a/apps/web/infra/web.ts +++ b/apps/web/infra/web.ts @@ -7,7 +7,7 @@ export const serviceSetup = (services: { web .namespace('islandis') .env({ - GRAPHQL_API_URL: ref((h) => `http://${h.svc(services.api)}`), + API_URL: ref((h) => `http://${h.svc(services.api)}`), TRACKING_DOMAIN: { dev: 'beta.dev01.devland.is', staging: 'beta.staging01.devland.is', diff --git a/apps/web/proxy.config.ts b/apps/web/proxy.config.ts index 0b7677f0cdd6..534f6a1cadf0 100644 --- a/apps/web/proxy.config.ts +++ b/apps/web/proxy.config.ts @@ -1,6 +1,6 @@ const proxyConfig = { '/api': { - target: process.env.GRAPHQL_API_URL ?? 'http://localhost:4444', + target: process.env.API_URL ?? 'http://localhost:4444', secure: false, }, } From 0964e5522dcde09244ecbfa449bf9ba173eccd2d Mon Sep 17 00:00:00 2001 From: andes-it Date: Thu, 21 Nov 2024 14:31:32 +0000 Subject: [PATCH 17/18] chore: charts update dirty files --- charts/islandis/values.dev.yaml | 2 +- charts/islandis/values.prod.yaml | 2 +- charts/islandis/values.staging.yaml | 2 +- charts/services/web/values.dev.yaml | 2 +- charts/services/web/values.prod.yaml | 2 +- charts/services/web/values.staging.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/charts/islandis/values.dev.yaml b/charts/islandis/values.dev.yaml index 8cbd2263e61b..cf7b2fabaa49 100644 --- a/charts/islandis/values.dev.yaml +++ b/charts/islandis/values.dev.yaml @@ -3373,11 +3373,11 @@ user-notification-worker: web: enabled: true env: + API_URL: 'http://web-api' DISABLE_API_CATALOGUE: 'false' DISABLE_ORGANIZATION_CHATBOT: 'false' DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'dev' - GRAPHQL_API_URL: 'http://web-api' LOG_LEVEL: 'info' NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' diff --git a/charts/islandis/values.prod.yaml b/charts/islandis/values.prod.yaml index 30d898f850d3..66ded2ed398d 100644 --- a/charts/islandis/values.prod.yaml +++ b/charts/islandis/values.prod.yaml @@ -3249,11 +3249,11 @@ user-notification-worker: web: enabled: true env: + API_URL: 'http://web-api' DISABLE_API_CATALOGUE: 'false' DISABLE_ORGANIZATION_CHATBOT: 'false' DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'prod' - GRAPHQL_API_URL: 'http://web-api' LOG_LEVEL: 'info' NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' diff --git a/charts/islandis/values.staging.yaml b/charts/islandis/values.staging.yaml index 52305bf966cb..f0836bbb7380 100644 --- a/charts/islandis/values.staging.yaml +++ b/charts/islandis/values.staging.yaml @@ -3111,11 +3111,11 @@ web: basicAuth: '/k8s/web/basic_auth' enabled: true env: + API_URL: 'http://web-api' DISABLE_API_CATALOGUE: 'false' DISABLE_ORGANIZATION_CHATBOT: 'false' DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'staging' - GRAPHQL_API_URL: 'http://web-api' LOG_LEVEL: 'info' NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' diff --git a/charts/services/web/values.dev.yaml b/charts/services/web/values.dev.yaml index 8c070d97cb86..a6455c2f5c34 100644 --- a/charts/services/web/values.dev.yaml +++ b/charts/services/web/values.dev.yaml @@ -19,11 +19,11 @@ global: name: 'web' enabled: true env: + API_URL: 'http://web-api' DISABLE_API_CATALOGUE: 'false' DISABLE_ORGANIZATION_CHATBOT: 'false' DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'dev' - GRAPHQL_API_URL: 'http://web-api' LOG_LEVEL: 'info' NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' diff --git a/charts/services/web/values.prod.yaml b/charts/services/web/values.prod.yaml index ad44e8e802a7..a5c86c5c9db1 100644 --- a/charts/services/web/values.prod.yaml +++ b/charts/services/web/values.prod.yaml @@ -19,11 +19,11 @@ global: name: 'web' enabled: true env: + API_URL: 'http://web-api' DISABLE_API_CATALOGUE: 'false' DISABLE_ORGANIZATION_CHATBOT: 'false' DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'prod' - GRAPHQL_API_URL: 'http://web-api' LOG_LEVEL: 'info' NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: 'driving-license-use-v1-endpoint-for-v2-comms' diff --git a/charts/services/web/values.staging.yaml b/charts/services/web/values.staging.yaml index a3f63a994525..4a0b40a3fa19 100644 --- a/charts/services/web/values.staging.yaml +++ b/charts/services/web/values.staging.yaml @@ -20,11 +20,11 @@ name: 'web' basicAuth: '/k8s/web/basic_auth' enabled: true env: + API_URL: 'http://web-api' DISABLE_API_CATALOGUE: 'false' DISABLE_ORGANIZATION_CHATBOT: 'false' DISABLE_SYSLUMENN_PAGE: 'false' ENVIRONMENT: 'staging' - GRAPHQL_API_URL: 'http://web-api' LOG_LEVEL: 'info' NODE_OPTIONS: '--max-old-space-size=691 -r dd-trace/init' SERVERSIDE_FEATURES_ON: '' From 9cf35bf2908c93aba28fb883cf286b81ad0e64eb Mon Sep 17 00:00:00 2001 From: Svana Date: Fri, 22 Nov 2024 10:27:17 +0000 Subject: [PATCH 18/18] Elastisearch docker-compose for offline tests --- apps/web/docker-compose.yml | 66 +++++++++++++++++++++++++++++++++++ apps/web/playwright.config.ts | 4 +-- apps/web/project.json | 8 +++++ 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 apps/web/docker-compose.yml diff --git a/apps/web/docker-compose.yml b/apps/web/docker-compose.yml new file mode 100644 index 000000000000..11ec2f126584 --- /dev/null +++ b/apps/web/docker-compose.yml @@ -0,0 +1,66 @@ +version: '3' +services: + elasticsearch: + image: docker.io/elasticsearch:8.8.0 + ports: + - 9200:9200 + - 9300:9300 + environment: + - discovery.type=single-node + - xpack.security.enabled=false + healthcheck: + test: ['CMD-SHELL', 'curl -f http://localhost:9200 || exit 1'] + interval: 10s + retries: 10 + + init-elasticsearch: + image: docker.io/curlimages/curl:7.85.0 + depends_on: + elasticsearch: + condition: service_healthy + entrypoint: > + sh -c " + until curl -s http://elasticsearch:9200; do + echo 'Waiting for Elasticsearch...'; + sleep 5; + done; + curl -X PUT 'http://elasticsearch:9200/island-is-kstnl' -H 'Content-Type: application/json' -d' + { + \"settings\": { + \"number_of_shards\": 1, + \"number_of_replicas\": 1 + }, + \"mappings\": { + \"properties\": { + \"title\": { + \"type\": \"text\", + \"fields\": { + \"sort\": { + \"type\": \"keyword\" + } + } + }, + \"dateUpdated\": { + \"type\": \"date\" + }, + \"dateCreated\": { + \"type\": \"date\" + }, + \"releaseDate\": { + \"type\": \"date\" + }, + \"tags\": { + \"type\": \"nested\", + \"properties\": { + \"key\": { + \"type\": \"keyword\" + }, + \"type\": { + \"type\": \"keyword\" + } + } + } + } + } + }'; + " diff --git a/apps/web/playwright.config.ts b/apps/web/playwright.config.ts index ed79a07fe22b..5bd18ea39c09 100644 --- a/apps/web/playwright.config.ts +++ b/apps/web/playwright.config.ts @@ -2,8 +2,8 @@ import { createPlaywrightConfig } from '@island.is/testing/e2e' const playwrightConfig = createPlaywrightConfig({ webServerUrl: 'http://localhost:4200', - command: - 'yarn infra run-local-env web --dependencies api --print --no-secrets --proxies', + app: 'web', + dependencies: ['api'], }) export default playwrightConfig diff --git a/apps/web/project.json b/apps/web/project.json index 9c2c9ffc8282..5c8fda302961 100644 --- a/apps/web/project.json +++ b/apps/web/project.json @@ -125,6 +125,14 @@ "parallel": false } }, + "dev-services": { + "executor": "nx:run-commands", + "options": { + "command": "docker compose up -d", + "cwd": "apps/web" + }, + "configurations": {} + }, "dev": { "executor": "nx:run-commands", "options": {