diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index f5765bd670..1ad47a033f 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -67,7 +67,7 @@ jobs: uses: actions/upload-artifact@v3 with: name: test-results - path: test-results + path: test/e2e/test-results check-code-formatting: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 6445ffc77d..60502aa4fc 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,6 @@ test/php/\.phpunit\.result\.cache node_modules .DS_Store docker-scan-results.txt -test-results/ -playwright-report/ +test-results +test-storage-state *storageState.json diff --git a/Makefile b/Makefile index eacebbde7b..f508db34dd 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ playwright-tests: .PHONY: playwright-app playwright-app: # delete any cached session storage state files if the service isn't running - docker compose ps app-for-playwright > /dev/null 2>&1 || rm -f *-storageState.json + docker compose ps app-for-playwright > /dev/null 2>&1 || $(MAKE) clean-test docker compose up -d app-for-playwright # wait until the app-for-playwright service is serving up HTTP before continuing until curl localhost:3238 > /dev/null 2>&1; do sleep 1; done @@ -83,9 +83,12 @@ clean: docker compose down docker system prune -f +clean-test: + cd test/e2e && npx rimraf test-storage-state test-results + .PHONY: clean-powerwash clean-powerwash: clean - npx rimraf *storageState.json test-results + $(MAKE) clean-test docker system prune -f --volumes - docker rmi -f `docker images -q "lf-*"` sillsdev/web-languageforge:base-php docker builder prune -f diff --git a/test/e2e/semantic-domains.spec.ts b/test/e2e/semantic-domains.spec.ts index 4d981f5ef3..a719284fc9 100644 --- a/test/e2e/semantic-domains.spec.ts +++ b/test/e2e/semantic-domains.spec.ts @@ -1,20 +1,13 @@ import { expect } from '@playwright/test'; import { test } from './utils/fixtures'; - -import { ProjectsPage } from './pages/projects.page'; - import { Project } from './utils/types'; - import { addLexEntry, addPictureFileToProject, initTestProject } from './utils/testSetup'; - - import constants from './testConstants.json'; import { EditorPage } from './pages/editor.page'; import { PageHeader } from './components/page-header.component'; import { ProjectSettingsPage } from './pages/project-settings.page'; test.describe('Lexicon E2E Semantic Domains Lazy Load', () => { - let projectsPageManager: ProjectsPage; let editorPage: EditorPage; let pageHeader: PageHeader; const project: Project = { @@ -26,11 +19,10 @@ test.describe('Lexicon E2E Semantic Domains Lazy Load', () => { const semanticDomain1dot1English = constants.testEntry1.senses[0].semanticDomain.values[0] + ' Sky'; const semanticDomain1dot1Thai = constants.testEntry1.senses[0].semanticDomain.values[0] + ' ท้องฟ้า'; - test.beforeAll(async ({ request, managerTab, member, manager, admin, }) => { + test.beforeAll(async ({ request, managerTab, manager, admin, }) => { project.id = await initTestProject(request, project.code, project.name, manager.username, [admin.username]); await addPictureFileToProject(request, project.code, constants.testEntry1.senses[0].pictures[0].fileName); await addLexEntry(request, project.code, constants.testEntry1); - projectsPageManager = new ProjectsPage(managerTab); editorPage = new EditorPage(managerTab, project); pageHeader = new PageHeader(editorPage.page); }); diff --git a/test/e2e/utils/fixtures.ts b/test/e2e/utils/fixtures.ts index d0a948362b..67ff0ca4e7 100644 --- a/test/e2e/utils/fixtures.ts +++ b/test/e2e/utils/fixtures.ts @@ -3,6 +3,7 @@ import { test as base } from '@playwright/test'; import type { Browser, Page } from '@playwright/test'; import type { E2EUsernames } from './e2e-users'; import constants from '../testConstants.json'; +import { getStorageStatePath } from './user-tools'; export type UserDetails = { username: string, @@ -21,7 +22,7 @@ function setupUserDetails(obj: UserDetails, username: E2EUsernames) { } const userTab = (username: E2EUsernames) => async ({ browser, browserName }: { browser: Browser, browserName: string}, use: (r: UserTab) => Promise) => { - const storageState = `${browserName}-${username}-storageState.json`; + const storageState = getStorageStatePath(browserName, username); const context = await browser.newContext({ storageState }) const page = await context.newPage(); const tab = page as UserTab; diff --git a/test/e2e/utils/login.ts b/test/e2e/utils/login.ts index 222b13a81f..576cc84463 100644 --- a/test/e2e/utils/login.ts +++ b/test/e2e/utils/login.ts @@ -1,6 +1,7 @@ import { Browser, Page } from '@playwright/test'; import constants from '../testConstants.json'; import type { E2EUsernames } from './e2e-users'; +import { getStorageStatePath } from './user-tools'; export async function login(page: Page, username: string, password: string) { await page.goto('/auth/login'); @@ -34,7 +35,9 @@ export function loginAs(page: Page, name: E2EUsernames) { return login(page, username, password); } -export async function getLoggedInPage(browser: Browser, name: string) { - const context = await browser.newContext({ storageState: `${name}-storageState.json` }); +export async function getLoggedInPage(browser: Browser, user: string) { + const browserName = browser.browserType().name(); + const storageState = getStorageStatePath(browserName, user); + const context = await browser.newContext({ storageState }); return await context.newPage(); } diff --git a/test/e2e/utils/user-tools.ts b/test/e2e/utils/user-tools.ts index 29e136d86d..0ab3254dac 100644 --- a/test/e2e/utils/user-tools.ts +++ b/test/e2e/utils/user-tools.ts @@ -4,6 +4,7 @@ import { loginAs } from "./login"; import { E2EUsernames } from "./e2e-users"; import * as fs from 'fs'; import constants from "../testConstants.json"; +import path from "path"; const SESSION_LIFETIME = 365 * 24 * 60 * 60 * 1000; // 1 year, in milliseconds @@ -21,7 +22,7 @@ export async function initUser(context: BrowserContext, user: E2EUsernames) { // Now log in and ensure there's a storage state saved const sessionCutoff = Date.now() - SESSION_LIFETIME; const browserName = context.browser().browserType().name(); - const path = `${browserName}-${user}-storageState.json`; + const path = getStorageStatePath(browserName, user); if (fs.existsSync(path) && fs.statSync(path)?.ctimeMs >= sessionCutoff) { // Storage state file is recent, no need to re-create it return; @@ -30,3 +31,13 @@ export async function initUser(context: BrowserContext, user: E2EUsernames) { await loginAs(page, user); await context.storageState({ path }); } + +export function getStorageStatePath(browser: string, user: string): string { + const testRoot = 'test/e2e'; + const storageRoot = 'test-storage-state' + const storageState = `${browser}-${user}-storageState.json`; + // true if running tests with VS-Code extension otherwise false + return process.cwd().endsWith(testRoot) + ? path.join(storageRoot, storageState) + : path.join(testRoot, storageRoot, storageState); +}