From 87d9e0c82db171f882a1f01e869654e37dc9d0b6 Mon Sep 17 00:00:00 2001 From: annieli555 Date: Sun, 28 Dec 2025 21:34:42 -0500 Subject: [PATCH 01/11] project save test --- tests/end2end/cloud-saving.spec.ts | 34 +++++++++++++++++++++ tests/end2end/header.spec.ts | 2 +- tests/end2end/page-headers.spec.ts | 2 +- tests/end2end/subtitle-contrast.ts | 2 +- tests/end2end/title.spec.ts | 2 +- tests/helpers/firestore.ts | 44 ++++++++++++++++++++++++++++ tests/{end2end => helpers}/goHome.ts | 0 7 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 tests/end2end/cloud-saving.spec.ts create mode 100644 tests/helpers/firestore.ts rename tests/{end2end => helpers}/goHome.ts (100%) diff --git a/tests/end2end/cloud-saving.spec.ts b/tests/end2end/cloud-saving.spec.ts new file mode 100644 index 000000000..0526478b5 --- /dev/null +++ b/tests/end2end/cloud-saving.spec.ts @@ -0,0 +1,34 @@ + +import { expect, test } from '../../playwright/fixtures'; +import { getTestDocument, listTestDocuments } from '../helpers/firestore'; + +test('editing a project saves it to the cloud', async ({ page }) => { + // The user is already logged in via the fixture. + await page.goto('/projects'); + + // Create a blank project + await page.getByTestId('addproject').click(); + + // Wait for project to be saved to the cloud + // Saves are debounced by 1 second, so wait at least that long + await page.waitForTimeout(2000); + + // Verify the project was saved to the cloud + const documents = await listTestDocuments('projects'); + expect(documents.length).toBeGreaterThan(0); + + const projectDoc = documents[documents.length - 1]; + const projectData = await getTestDocument('projects', projectDoc.id); + expect(projectData).toBeDefined(); + + // Make an edit to the project + const newProjectName = "What's in a name"; + await page.locator('#project-name').fill(newProjectName); + + // Wait for project to be saved to the cloud + await page.waitForTimeout(2000); + + // Verify the edit was saved to the cloud + const updatedProjectData = await getTestDocument('projects', projectDoc.id); + expect(updatedProjectData?.name).toBe(newProjectName); +}); \ No newline at end of file diff --git a/tests/end2end/header.spec.ts b/tests/end2end/header.spec.ts index 2ec7518e2..724eacc4a 100644 --- a/tests/end2end/header.spec.ts +++ b/tests/end2end/header.spec.ts @@ -1,5 +1,5 @@ import { expect, test } from '@playwright/test'; -import goHome from './goHome'; +import goHome from '../helpers/goHome'; test('has Wordplay header', async ({ page }) => { await goHome(page); diff --git a/tests/end2end/page-headers.spec.ts b/tests/end2end/page-headers.spec.ts index 5b4f9f9e6..9909ebd52 100644 --- a/tests/end2end/page-headers.spec.ts +++ b/tests/end2end/page-headers.spec.ts @@ -1,5 +1,5 @@ import { expect, test, type Page } from '@playwright/test'; -import goHome from './goHome'; +import goHome from '../helpers/goHome'; async function clickLinkAndCheckHeader(page: Page, linkAndHeader: string) { await goHome(page); diff --git a/tests/end2end/subtitle-contrast.ts b/tests/end2end/subtitle-contrast.ts index 3b32c242b..4a7349f1b 100644 --- a/tests/end2end/subtitle-contrast.ts +++ b/tests/end2end/subtitle-contrast.ts @@ -1,7 +1,7 @@ import AxeBuilder from '@axe-core/playwright'; import { expect, test } from '@playwright/test'; import type { AxeResults } from 'axe-core'; -import goHome from './goHome'; +import goHome from '../helpers/goHome'; // Print out the accessibility scan results from AxeBuilder. function printAccessibilityScanResults(axeBuilderScanResults: AxeResults) { diff --git a/tests/end2end/title.spec.ts b/tests/end2end/title.spec.ts index 3a69dbe6d..1a5a15a1e 100644 --- a/tests/end2end/title.spec.ts +++ b/tests/end2end/title.spec.ts @@ -1,5 +1,5 @@ import { expect, test } from '@playwright/test'; -import goHome from './goHome'; +import goHome from '../helpers/goHome'; test('has Wordplay window title', async ({ page }) => { await goHome(page); diff --git a/tests/helpers/firestore.ts b/tests/helpers/firestore.ts new file mode 100644 index 000000000..65107a5f0 --- /dev/null +++ b/tests/helpers/firestore.ts @@ -0,0 +1,44 @@ +import { initializeApp, type App } from 'firebase-admin/app'; +import { getFirestore, type Firestore } from 'firebase-admin/firestore'; + +let testApp: App | null = null; +let firestoreInstance: Firestore | null = null; + +export function getTestFirestore(): Firestore { + if (firestoreInstance) { + return firestoreInstance; + } + + process.env.FIRESTORE_EMULATOR_HOST = 'localhost:8080'; + + testApp = initializeApp({ + projectId: 'demo', + }); + + firestoreInstance = getFirestore(testApp); + return firestoreInstance; +} + +export async function getTestDocument( + collectionName: string, + documentId: string, +) { + const firestore = getTestFirestore(); + const docRef = firestore.collection(collectionName).doc(documentId); + const docSnap = await docRef.get(); + + if (docSnap.exists) { + return docSnap.data(); + } + return null; +} + +export async function listTestDocuments(collectionName: string) { + const firestore = getTestFirestore(); + const snapshot = await firestore.collection(collectionName).get(); + + return snapshot.docs.map((doc) => ({ + id: doc.id, + data: doc.data(), + })); +} diff --git a/tests/end2end/goHome.ts b/tests/helpers/goHome.ts similarity index 100% rename from tests/end2end/goHome.ts rename to tests/helpers/goHome.ts From 35d27f7bee522f11c84f2cb0c53e356d3b50cd6c Mon Sep 17 00:00:00 2001 From: annieli555 Date: Sun, 4 Jan 2026 20:08:15 -0500 Subject: [PATCH 02/11] character save test and character name update test, helpers --- playwright/fixtures.ts | 17 ++- .../characters/NewCharacterButton.svelte | 1 + tests/end2end/cloud-saving.spec.ts | 34 ------ tests/end2end/cloud-updates.spec.ts | 115 ++++++++++++++++++ tests/helpers/createCharacter.ts | 15 +++ tests/helpers/createProject.ts | 15 +++ tests/helpers/firestore.ts | 80 ++++++++++-- 7 files changed, 230 insertions(+), 47 deletions(-) delete mode 100644 tests/end2end/cloud-saving.spec.ts create mode 100644 tests/end2end/cloud-updates.spec.ts create mode 100644 tests/helpers/createCharacter.ts create mode 100644 tests/helpers/createProject.ts diff --git a/playwright/fixtures.ts b/playwright/fixtures.ts index b58f89c67..b3098e821 100644 --- a/playwright/fixtures.ts +++ b/playwright/fixtures.ts @@ -3,7 +3,20 @@ import fs from 'fs'; import path from 'path'; export * from '@playwright/test'; -export const test = baseTest.extend<{}, { workerStorageState: string }>({ + +/** Generates a worker-specific username based on parallelIndex */ +function getUsernameForWorker(): string { + return `user${test.info().parallelIndex}`; +} + +export const test = baseTest.extend< + { loggedInUsername: string }, + { workerStorageState: string } +>({ + // Provide the test username to all tests in this worker. + loggedInUsername: async ({ }, use) => { + await use(getUsernameForWorker()); + }, // Use the same storage state for all tests in this worker. storageState: ({ workerStorageState }, use) => use(workerStorageState), // Authenticate once per worker with a worker-scoped fixture. @@ -30,7 +43,7 @@ export const test = baseTest.extend<{}, { workerStorageState: string }>({ // Make sure that accounts are unique, so that multiple team members // can run tests at the same time without interference. const account = { - username: `user${id}`, + username: getUsernameForWorker(), password: 'password', }; diff --git a/src/routes/characters/NewCharacterButton.svelte b/src/routes/characters/NewCharacterButton.svelte index dc4cbe6d4..03939b116 100644 --- a/src/routes/characters/NewCharacterButton.svelte +++ b/src/routes/characters/NewCharacterButton.svelte @@ -28,6 +28,7 @@ background={inline} tip={(l) => l.ui.page.characters.button.new} action={addCharacter} + testid="newcharacter" active={!creating} large={!inline} icon="+" diff --git a/tests/end2end/cloud-saving.spec.ts b/tests/end2end/cloud-saving.spec.ts deleted file mode 100644 index 0526478b5..000000000 --- a/tests/end2end/cloud-saving.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ - -import { expect, test } from '../../playwright/fixtures'; -import { getTestDocument, listTestDocuments } from '../helpers/firestore'; - -test('editing a project saves it to the cloud', async ({ page }) => { - // The user is already logged in via the fixture. - await page.goto('/projects'); - - // Create a blank project - await page.getByTestId('addproject').click(); - - // Wait for project to be saved to the cloud - // Saves are debounced by 1 second, so wait at least that long - await page.waitForTimeout(2000); - - // Verify the project was saved to the cloud - const documents = await listTestDocuments('projects'); - expect(documents.length).toBeGreaterThan(0); - - const projectDoc = documents[documents.length - 1]; - const projectData = await getTestDocument('projects', projectDoc.id); - expect(projectData).toBeDefined(); - - // Make an edit to the project - const newProjectName = "What's in a name"; - await page.locator('#project-name').fill(newProjectName); - - // Wait for project to be saved to the cloud - await page.waitForTimeout(2000); - - // Verify the edit was saved to the cloud - const updatedProjectData = await getTestDocument('projects', projectDoc.id); - expect(updatedProjectData?.name).toBe(newProjectName); -}); \ No newline at end of file diff --git a/tests/end2end/cloud-updates.spec.ts b/tests/end2end/cloud-updates.spec.ts new file mode 100644 index 000000000..d90a2b84c --- /dev/null +++ b/tests/end2end/cloud-updates.spec.ts @@ -0,0 +1,115 @@ + +import { expect, test } from '../../playwright/fixtures'; +import { createTestCharacter } from '../helpers/createCharacter'; +import { createTestProject } from '../helpers/createProject'; +import { updateProjectSource, waitForDocumentUpdate } from '../helpers/firestore'; + +test('editing a project saves it to the cloud', async ({ page }) => { + // Create test project - the page will be redirected to the new project page + const projectId = await createTestProject(page); + + // Make an edit to the project + const newProjectName = "What's in a name"; + const projectNameField = page.locator('#project-name'); + await projectNameField.fill(newProjectName); + expect(await projectNameField.inputValue()).toBe(newProjectName); + + // Wait for the project to be updated in Firestore + const updatedProjectData = await waitForDocumentUpdate( + page, + 'projects', + projectId, + (data) => data?.name === newProjectName, + ); + + // Verify the edit was saved to the cloud + expect(updatedProjectData?.name).toBe(newProjectName); +}); + + +test('editing a custom character saves it to the cloud', async ({ + page, + loggedInUsername, +}) => { + // Create test character - the page will be redirected to the new character page + const characterId = await createTestCharacter(page); + + // Make an edit to the character + const characterNameInput = 'My Cool Character'; + await page.locator('#character-name').fill(characterNameInput); + + // Wait for the character to be updated in Firestore + const expectedFullName = `${loggedInUsername}/${characterNameInput}`; + const updatedCharacterData = await waitForDocumentUpdate( + page, + 'characters', + characterId, + (data) => data?.name === expectedFullName, + ); + + // Verify the edit was saved to the cloud + expect(updatedCharacterData?.name).toBe(expectedFullName); +}); + +test('changing a character name updates its project references', async ({ + page, + loggedInUsername, +}) => { + // Create test character - the page will be redirected to the new character page + const characterId = await createTestCharacter(page); + + // Set a name for the character since the default is empty + const characterNameInput = page.locator('#character-name'); + const initialCharacterName = 'Old'; + await characterNameInput.fill(initialCharacterName); + + // Wait for it to save + const initialCharacterNameFull = `${loggedInUsername}/${initialCharacterName}`; + await waitForDocumentUpdate( + page, + 'characters', + characterId, + (data) => data?.name === initialCharacterNameFull, + ); + + // Create a test project - this will redirect to the project page + const projectId = await createTestProject(page); + + // Wait for the project to be saved to Firestore + await waitForDocumentUpdate( + page, + 'projects', + projectId, + (data) => data?.id === projectId, + ); + + // Update the project source to include a reference to the character + const sourceCodeWithCharacterRef = `Phrase(\`@${initialCharacterNameFull}\`)`; + await updateProjectSource(projectId, sourceCodeWithCharacterRef); + + // Now, rename the character + await page.goto(`/character/${characterId}`); + const newCharacterName = 'New'; + await page.locator('#character-name').fill(newCharacterName); + + // Wait for the character to be updated in Firestore + const expectedFullName = `${loggedInUsername}/${newCharacterName}`; + await waitForDocumentUpdate( + page, + 'characters', + characterId, + (data) => data?.name === expectedFullName, + ); + + // Wait for the project to be updated with the new character reference + const expectedSourceCode = `Phrase(\`@${expectedFullName}\`)`; + const updatedProject = await waitForDocumentUpdate( + page, + 'projects', + projectId, + (data) => data?.sources?.[0]?.code === expectedSourceCode, + ); + + // Verify the character reference was updated in the project + expect(updatedProject?.sources[0].code).toBe(expectedSourceCode); +}); \ No newline at end of file diff --git a/tests/helpers/createCharacter.ts b/tests/helpers/createCharacter.ts new file mode 100644 index 000000000..ba03ebbe7 --- /dev/null +++ b/tests/helpers/createCharacter.ts @@ -0,0 +1,15 @@ +import type { Page } from '@playwright/test'; + +export async function createTestCharacter(page: Page): Promise { + // Create a new character + await page.goto('/characters'); + await page.getByTestId('newcharacter').click(); + + // Wait for the URL to redirect to the new character page + await page.waitForURL(/\/character\/[^/]+$/); + + // Extract the character ID from the URL + const url = page.url(); + const characterId = url.split('/').pop() as string; + return characterId; +} \ No newline at end of file diff --git a/tests/helpers/createProject.ts b/tests/helpers/createProject.ts new file mode 100644 index 000000000..496b6bf84 --- /dev/null +++ b/tests/helpers/createProject.ts @@ -0,0 +1,15 @@ +import type { Page } from '@playwright/test'; + +export async function createTestProject(page: Page): Promise { + // Create a new project + await page.goto('/projects'); + await page.getByTestId('addproject').click(); + + // Wait for the page to redirect to the new project + await page.waitForURL(/\/project\/[^/]+$/); + + // Extract the project ID from the URL + const url = page.url(); + const projectId = url.split('/').pop() as string; + return projectId; +} \ No newline at end of file diff --git a/tests/helpers/firestore.ts b/tests/helpers/firestore.ts index 65107a5f0..8fda40157 100644 --- a/tests/helpers/firestore.ts +++ b/tests/helpers/firestore.ts @@ -1,17 +1,18 @@ -import { initializeApp, type App } from 'firebase-admin/app'; +import type { Page } from '@playwright/test'; +import { initializeApp } from 'firebase-admin/app'; import { getFirestore, type Firestore } from 'firebase-admin/firestore'; -let testApp: App | null = null; let firestoreInstance: Firestore | null = null; +/** + * Returns the Firestore instance used for testing. + */ export function getTestFirestore(): Firestore { if (firestoreInstance) { return firestoreInstance; } - process.env.FIRESTORE_EMULATOR_HOST = 'localhost:8080'; - - testApp = initializeApp({ + const testApp = initializeApp({ projectId: 'demo', }); @@ -19,6 +20,9 @@ export function getTestFirestore(): Firestore { return firestoreInstance; } +/** + * Fetches a specific document from the test Firestore database. + */ export async function getTestDocument( collectionName: string, documentId: string, @@ -33,12 +37,66 @@ export async function getTestDocument( return null; } -export async function listTestDocuments(collectionName: string) { +/** + * Updates a project's source code in Firestore directly. + * Useful for setting up test scenarios without going through the UI. + */ +export async function updateProjectSource( + projectId: string, + sourceCode: string, +): Promise { const firestore = getTestFirestore(); - const snapshot = await firestore.collection(collectionName).get(); + const projectRef = firestore.collection('projects').doc(projectId); + + const projectSnap = await projectRef.get(); + if (!projectSnap.exists) { + throw new Error(`Project ${projectId} not found in Firestore`); + } + + const projectData = projectSnap.data(); + + if (projectData?.sources && Array.isArray(projectData.sources) && projectData.sources.length > 0) { + projectData.sources[0].code = sourceCode; + + await projectRef.update({ + sources: projectData.sources, + timestamp: Date.now(), + }); + } else { + throw new Error(`Could not update project source: project ${projectId} has missing or invalid sources field`); + } +} + +/** + * Waits for a document in Firestore to meet a specific condition. + * Useful when waiting for updates to be saved to the cloud. + * + * @param page - The Playwright page (needed for waitForTimeout) + * @param collectionName - The collection name + * @param documentId - The document ID + * @param predicate - A function that takes the document data and returns true when the condition is met + * @param timeout - Maximum time to wait in milliseconds (default: 5000) + * @param interval - Polling interval in milliseconds (default: 100) + * @returns The document data when the condition is met, or after the check has timed out + */ +export async function waitForDocumentUpdate( + page: Page, + collectionName: string, + documentId: string, + predicate: (data: FirebaseFirestore.DocumentData | null | undefined) => boolean, + timeout = 5000, + interval = 100, +) { + let documentData; + const startTime = Date.now(); + + while (Date.now() - startTime < timeout) { + documentData = await getTestDocument(collectionName, documentId); + if (documentData && predicate(documentData)) { + break; + } + await page.waitForTimeout(interval); + } - return snapshot.docs.map((doc) => ({ - id: doc.id, - data: doc.data(), - })); + return documentData; } From 2bf7ecaba63e2000ec0006a63979a943b916cc42 Mon Sep 17 00:00:00 2001 From: annieli555 Date: Sun, 4 Jan 2026 21:08:34 -0500 Subject: [PATCH 03/11] see if logs reveal anything --- .github/workflows/playwright.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 9315dc114..19048e7fa 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -30,7 +30,7 @@ jobs: - name: Build project run: npm run build - name: Run end-to-end tests with emulator - run: firebase emulators:exec "npx playwright test --reporter=list" --project=demo-wordplay --log-verbosity QUIET + run: firebase emulators:exec "npx playwright test --reporter=list" --project=demo-wordplay - uses: actions/upload-artifact@v4 if: always() with: From 9304862e79952267f33e47b97c470706921bab02 Mon Sep 17 00:00:00 2001 From: annieli555 Date: Mon, 5 Jan 2026 22:43:27 -0500 Subject: [PATCH 04/11] shorter timeout, debug logs --- .github/workflows/playwright.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 19048e7fa..8569d0372 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -7,7 +7,7 @@ on: - main jobs: test: - timeout-minutes: 60 + timeout-minutes: 5 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -31,6 +31,8 @@ jobs: run: npm run build - name: Run end-to-end tests with emulator run: firebase emulators:exec "npx playwright test --reporter=list" --project=demo-wordplay + env: + DEBUG: "*" - uses: actions/upload-artifact@v4 if: always() with: From 343461736fab26ac62af86acbb57ff36f68b51e5 Mon Sep 17 00:00:00 2001 From: annieli555 Date: Mon, 5 Jan 2026 22:58:26 -0500 Subject: [PATCH 05/11] hanging on SMTP_PASSWORD prompt? --- .github/workflows/playwright.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 8569d0372..00ba593b0 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -17,7 +17,7 @@ jobs: - name: Install dependencies run: npm ci - run: echo "${{ secrets.ENV_DEMO }}" > .env - - run: echo "${{ secrets.FUNCTIONS_ENV_DEMO }}" > functions/.env + - run: echo "SMTP_PASSWORD=dummy-password-for-ci" > functions/.env - name: Set up JDK 21 # Firebase tools requires >=21 uses: actions/setup-java@v4 with: From 84409b01ea932227fd785f9f24c285f793e2d846 Mon Sep 17 00:00:00 2001 From: annieli555 Date: Tue, 6 Jan 2026 22:18:33 -0500 Subject: [PATCH 06/11] made progress with updated functions/.env, try normally --- .github/workflows/playwright.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 00ba593b0..0464c93bc 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -7,7 +7,7 @@ on: - main jobs: test: - timeout-minutes: 5 + timeout-minutes: 60 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -31,8 +31,6 @@ jobs: run: npm run build - name: Run end-to-end tests with emulator run: firebase emulators:exec "npx playwright test --reporter=list" --project=demo-wordplay - env: - DEBUG: "*" - uses: actions/upload-artifact@v4 if: always() with: From 0760244f5528f4ebf3520d93ac38fb0056ca9a3f Mon Sep 17 00:00:00 2001 From: annieli555 Date: Fri, 9 Jan 2026 21:07:22 -0500 Subject: [PATCH 07/11] use the right emulator project ID --- tests/helpers/firestore.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/helpers/firestore.ts b/tests/helpers/firestore.ts index 8fda40157..21b4b7cac 100644 --- a/tests/helpers/firestore.ts +++ b/tests/helpers/firestore.ts @@ -13,10 +13,17 @@ export function getTestFirestore(): Firestore { } const testApp = initializeApp({ - projectId: 'demo', + projectId: 'demo-wordplay', }); firestoreInstance = getFirestore(testApp); + + // Connect to the Firestore emulator + firestoreInstance.settings({ + host: 'localhost:8080', + ssl: false, + }); + return firestoreInstance; } From c38c0f7ab702c4a8d66bd247aa05fb071d30692f Mon Sep 17 00:00:00 2001 From: annieli555 Date: Fri, 9 Jan 2026 21:23:25 -0500 Subject: [PATCH 08/11] bring back log verbosity --- .github/workflows/playwright.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 0464c93bc..af638262e 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -30,7 +30,7 @@ jobs: - name: Build project run: npm run build - name: Run end-to-end tests with emulator - run: firebase emulators:exec "npx playwright test --reporter=list" --project=demo-wordplay + run: firebase emulators:exec "npx playwright test --reporter=list" --project=demo-wordplay --log-verbosity QUIET - uses: actions/upload-artifact@v4 if: always() with: From 36eedefaa2ab268905de91bd1c075685dccdf6c9 Mon Sep 17 00:00:00 2001 From: annieli555 Date: Fri, 9 Jan 2026 21:36:10 -0500 Subject: [PATCH 09/11] stop using dummy password --- .github/workflows/playwright.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index af638262e..9315dc114 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -17,7 +17,7 @@ jobs: - name: Install dependencies run: npm ci - run: echo "${{ secrets.ENV_DEMO }}" > .env - - run: echo "SMTP_PASSWORD=dummy-password-for-ci" > functions/.env + - run: echo "${{ secrets.FUNCTIONS_ENV_DEMO }}" > functions/.env - name: Set up JDK 21 # Firebase tools requires >=21 uses: actions/setup-java@v4 with: From 9cd86d326f8fb3254290cf2de3ec1545c384c181 Mon Sep 17 00:00:00 2001 From: annieli555 Date: Fri, 9 Jan 2026 21:47:04 -0500 Subject: [PATCH 10/11] append to functions/.env --- .github/workflows/playwright.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 9315dc114..7cb92fe52 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -17,7 +17,7 @@ jobs: - name: Install dependencies run: npm ci - run: echo "${{ secrets.ENV_DEMO }}" > .env - - run: echo "${{ secrets.FUNCTIONS_ENV_DEMO }}" > functions/.env + - run: echo "${{ secrets.FUNCTIONS_ENV_DEMO }}" > functions/.env && echo "SMTP_PASSWORD=" >> functions/.env - name: Set up JDK 21 # Firebase tools requires >=21 uses: actions/setup-java@v4 with: From 1ed7eb7e362bb60eeaf679bc7f7d499b9b782fdc Mon Sep 17 00:00:00 2001 From: annieli555 Date: Fri, 9 Jan 2026 22:22:36 -0500 Subject: [PATCH 11/11] toggle docs tile in project test --- tests/end2end/project.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/end2end/project.spec.ts b/tests/end2end/project.spec.ts index 84e6b4850..1becfde2f 100644 --- a/tests/end2end/project.spec.ts +++ b/tests/end2end/project.spec.ts @@ -15,6 +15,9 @@ test('create project and visit its tiles ', async ({ page }) => { // Click to open the collaboration panel await page.getByTestId('collaborate-toggle').click(); + // Click to open the documentation panel + await page.getByTestId('docs-toggle').click(); + // Expect all tiles to be visible. await Promise.all([ expect(page.getByTestId('tile-output')).toBeVisible(),