Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/CICD.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ jobs:
matrix:
browser:
- chrome
# - firefox
- firefox
- edge
viewport:
[
"viewportWidth=375,viewportHeight=667",
Expand All @@ -61,7 +62,7 @@ jobs:
if: always()
uses: actions/upload-artifact@v4
with:
name: videos
name: videos-${{ matrix.browser }}-${{ strategy.job-index }}
path: cypress/videos
retention-days: 5

Expand Down
17 changes: 17 additions & 0 deletions cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,22 @@ export default defineConfig({
allowCypressEnv: false,
e2e: {
baseUrl: "http://localhost:5173",
setupNodeEvents(on, config) {
on('before:browser:launch', (browser, launchOptions) => {
if (browser.name === 'firefox') {
// Firefox doesn't auto-download files; configure it to save
// directly to the Cypress downloads folder without prompting.
launchOptions.preferences['browser.download.folderList'] = 2;
launchOptions.preferences['browser.download.dir'] =
config.downloadsFolder;
launchOptions.preferences[
'browser.helperApps.neverAsk.saveToDisk'
] =
'text/csv,application/octet-stream,application/yaml,text/yaml,text/plain,application/x-yaml';
launchOptions.preferences['pdfjs.disabled'] = true;
}
return launchOptions;
});
},
},
});
1 change: 1 addition & 0 deletions cypress/e2e/Card.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ context('Card', () => {
.first()
.find('[data-name=card-author-input]')
.type('Test Author{enter}');
cy.get('[data-name=card]:visible').should('exist');
});

beforeEach(() => {
Expand Down
9 changes: 9 additions & 0 deletions cypress/e2e/ConnectionLost.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ context('ConnectionLost', () => {
cy.get('[data-name=rank]:visible').should('exist');
});

// Firefox keeps navigator.onLine = false across navigations when the
// offline event was dispatched programmatically. Restoring online state
// here prevents Firebase auth from failing in the next beforeEach or the
// after hook.
afterEach(() => {
cy.window().then((win) => win.dispatchEvent(new Event('online')));
});

it('shows a connection lost alert when the browser goes offline', () => {
cy.window().then((win) => win.dispatchEvent(new Event('offline')));
cy.get('[data-name=error-alert]').should('be.visible');
Expand All @@ -34,6 +42,7 @@ context('ConnectionLost', () => {
});

after(() => {
cy.window().then((win) => win.dispatchEvent(new Event('online')));
cy.deleteAllBoards();
});
});
9 changes: 5 additions & 4 deletions cypress/e2e/Menu.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ context('Menu', () => {

it('csv created_at timestamp is within 24 hours of the current time', () => {
const cardText = 'Timestamp test card';
const date = new Date().toISOString().slice(0, 10);
const csvPath = `cypress/downloads/Test Board Name-${date}.csv`;

cy.get('[data-name=rank]:visible')
.first()
Expand All @@ -191,13 +193,12 @@ context('Menu', () => {
.should('have.value', '');
cy.get('[data-name=card]:visible').should('exist');

// Delete any existing file so Firefox doesn't rename the new download.
cy.exec(`rm -f "${csvPath}"`);
cy.get('[data-name=menu-button]').click();
cy.get('[data-name=download-csv-button]').click();

const date = new Date().toISOString().slice(0, 10);
// Use .should() so Cypress retries readFile until the new download
// overwrites a stale CSV from an earlier test in this suite.
cy.readFile(`cypress/downloads/Test Board Name-${date}.csv`)
cy.readFile(csvPath)
.should('include', cardText)
.then((csv) => {
const [, ...rows] = csv.trim().split('\n');
Expand Down
25 changes: 16 additions & 9 deletions cypress/e2e/OwnerRealtimeSync.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,28 @@ context('OwnerRealtimeSync', () => {
// Owner loads the board — with the fix, a Firestore subscription is established
// for owners when open_permission is active
cy.login('owner');
// Capture the session cookie now, before cy.visit() causes the app to call
// /auth again. In Firefox, that re-auth can overwrite __session with a new
// anonymous-user token that doesn't own the board, causing PATCH → 403.
cy.getCookie('__session').as('ownerSession');
cy.visit(boardUrl);
cy.get('[data-name=rank]:visible').should('exist');
cy.get('[data-name=vote-button]:visible').should('exist');

// PATCH the board via REST, bypassing the Svelte store entirely.
// Only the Firestore subscription — not the local store listener — can deliver this update.
cy.request(`/boards/${boardId}`).then(({ body }) => {
let data = body.data;
try {
data = JSON.parse(data);
} catch {}
cy.request({
method: 'PATCH',
url: `/boards/${boardId}`,
body: { ...body, data, voting_open: false },
cy.get('@ownerSession').then((cookie) => {
cy.request(`/boards/${boardId}`).then(({ body }) => {
let data = body.data;
try {
data = JSON.parse(data);
} catch {}
cy.request({
method: 'PATCH',
url: `/boards/${boardId}`,
body: { ...body, data, voting_open: false },
headers: { Cookie: `__session=${cookie.value}` },
});
});
});

Expand Down
5 changes: 3 additions & 2 deletions cypress/e2e/TemplateRoundTrip.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,10 +276,11 @@ context(
// Rename the first column — this removes the i18n key from the export
customiseFirstRank({ name: 'My Custom Column' });

// Delete the file from the German-export test so Firefox doesn't save
// the new download under a deduplicated name (e.g. "file (1).yaml").
cy.exec(`rm -f "${DOWNLOAD_FILE}"`);
downloadTemplate();

// The file already exists from the German-export test in this context.
// Use .should() so Cypress retries readFile until the download overwrites it.
cy.readFile(DOWNLOAD_FILE)
.should('include', 'My Custom Column')
.then((text) => {
Expand Down
16 changes: 16 additions & 0 deletions cypress/support/e2e.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
// Firefox aborts in-flight fetch() calls during navigation and surfaces them
// as "NetworkError when attempting to fetch resource" unhandled rejections.
// Chrome drops the same aborted requests silently. Returning false here tells
// Cypress not to fail the test for this browser-specific behaviour.
Cypress.on('uncaught:exception', (err) => {
// Firefox reports aborted fetch calls during navigation as NetworkError.
if (err.message.includes('NetworkError when attempting to fetch resource')) {
return false;
}
// Firebase auth can fail with this when the browser is in a simulated
// offline state (navigator.onLine = false in Firefox).
if (err.message.includes('auth/network-request-failed')) {
return false;
}
});

Cypress.Commands.add('login', (name = 'owner') => {
cy.session(
name,
Expand Down
Loading