mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-04-09 10:00:51 -04:00
feat: convert failed updates test to Playwright (#54761)
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
@@ -1,55 +0,0 @@
|
||||
import store from 'store';
|
||||
import { ChallengeData } from '../../../../../tools/challenge-editor/api/interfaces/challenge-data';
|
||||
|
||||
const failedUpdates = [
|
||||
{
|
||||
endpoint: '/modern-challenge-completed',
|
||||
payload: { id: '5dc1798ff86c76b9248c6eb3', challengeType: 0 },
|
||||
id: '4bd1d704-cfaa-44f7-92a3-bc0d857dbaa6'
|
||||
},
|
||||
{
|
||||
endpoint: '/modern-challenge-completed',
|
||||
payload: { id: '5dc17d3bf86c76b9248c6eb4', challengeType: 0 },
|
||||
id: 'ea289e2f-a5d2-45e0-b795-0f9f4afc5124'
|
||||
}
|
||||
];
|
||||
const failedUpdatesKey = 'fcc-failed-updates';
|
||||
|
||||
function getCompletedIds(completedChallenges: ChallengeData[]): string[] {
|
||||
return completedChallenges.map((challenge: ChallengeData) => challenge.id);
|
||||
}
|
||||
|
||||
describe('failed update flushing', { browser: 'chrome' }, function () {
|
||||
before(() => {
|
||||
cy.task('seed');
|
||||
cy.login();
|
||||
});
|
||||
|
||||
it('should resubmit failed updates, check they are stored, then flush', () => {
|
||||
store.set(failedUpdatesKey, failedUpdates);
|
||||
cy.request('http://localhost:3000/user/get-session-user')
|
||||
.its('body.user.developmentuser.completedChallenges')
|
||||
.then(
|
||||
(completedChallenges: ChallengeData[]) =>
|
||||
expect(completedChallenges).to.be.empty
|
||||
);
|
||||
|
||||
cy.intercept('http://localhost:3000/modern-challenge-completed').as(
|
||||
'completed'
|
||||
);
|
||||
cy.wrap(store.get(failedUpdatesKey)).should('deep.equal', failedUpdates);
|
||||
cy.visit('/');
|
||||
cy.wait('@completed');
|
||||
// if we don't wait for both requests to complete, we have a race condition
|
||||
cy.wait('@completed');
|
||||
cy.request('http://localhost:3000/user/get-session-user')
|
||||
.its('body.user.developmentuser.completedChallenges')
|
||||
.then((completedChallenges: ChallengeData[]) => {
|
||||
const completedIds: string[] = getCompletedIds(completedChallenges);
|
||||
failedUpdates.forEach(failedUpdate => {
|
||||
expect(completedIds).to.include(failedUpdate.payload.id);
|
||||
});
|
||||
expect(store.get(failedUpdatesKey)).to.be.empty;
|
||||
});
|
||||
});
|
||||
});
|
||||
85
e2e/failed-updates.spec.ts
Normal file
85
e2e/failed-updates.spec.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { execSync } from 'child_process';
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { ChallengeData } from '../tools/challenge-editor/api/interfaces/challenge-data';
|
||||
|
||||
const failedUpdates = [
|
||||
{
|
||||
endpoint: '/modern-challenge-completed',
|
||||
payload: { id: '5dc1798ff86c76b9248c6eb3', challengeType: 0 },
|
||||
id: '4bd1d704-cfaa-44f7-92a3-bc0d857dbaa6'
|
||||
},
|
||||
{
|
||||
endpoint: '/modern-challenge-completed',
|
||||
payload: { id: '5dc17d3bf86c76b9248c6eb4', challengeType: 0 },
|
||||
id: 'ea289e2f-a5d2-45e0-b795-0f9f4afc5124'
|
||||
}
|
||||
];
|
||||
const storeKey = 'fcc-failed-updates';
|
||||
|
||||
function getCompletedIds(completedChallenges: ChallengeData[]): string[] {
|
||||
return completedChallenges.map((challenge: ChallengeData) => challenge.id);
|
||||
}
|
||||
test.use({ storageState: 'playwright/.auth/development-user.json' });
|
||||
|
||||
test.beforeAll(() => {
|
||||
execSync('node ./tools/scripts/seed/seed-demo-user');
|
||||
});
|
||||
|
||||
test.afterAll(() => {
|
||||
execSync('node ./tools/scripts/seed/seed-demo-user certified-user');
|
||||
});
|
||||
|
||||
test.describe('failed update flushing', () => {
|
||||
test('should resubmit failed updates to the api and clear the store', async ({
|
||||
page,
|
||||
request
|
||||
}) => {
|
||||
// Initially, the user has no completed challenges.
|
||||
const userRes = await request.get(
|
||||
'http://localhost:3000/user/get-session-user'
|
||||
);
|
||||
const completedChallenges = (await userRes.json()).user.developmentuser
|
||||
.completedChallenges;
|
||||
expect(completedChallenges).toEqual([]);
|
||||
|
||||
// It's necessary to wait until the page has loaded before setting the
|
||||
// localStorage. Otherwise, evaluate fails with a permissions error (the
|
||||
// store doesn't exist yet).
|
||||
await page.goto('/');
|
||||
await page.evaluate(
|
||||
([failedUpdates, storeKey]) => {
|
||||
localStorage.setItem(storeKey, JSON.stringify(failedUpdates));
|
||||
},
|
||||
[failedUpdates, storeKey] as const
|
||||
);
|
||||
|
||||
// The update epic sends two requests and this lets us wait for both.
|
||||
const submitRes = page
|
||||
.waitForResponse('http://localhost:3000/modern-challenge-completed')
|
||||
.then(() =>
|
||||
page.waitForResponse('http://localhost:3000/modern-challenge-completed')
|
||||
);
|
||||
|
||||
await page.reload();
|
||||
await submitRes;
|
||||
|
||||
const updatedUserRes = await request.get(
|
||||
'http://localhost:3000/user/get-session-user'
|
||||
);
|
||||
|
||||
// Now the user should have both completed challenges.
|
||||
const updatedCompletedChallenges = (await updatedUserRes.json()).user
|
||||
.developmentuser.completedChallenges;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
const completedIds = getCompletedIds(updatedCompletedChallenges);
|
||||
|
||||
for (const { payload } of failedUpdates) {
|
||||
expect(completedIds).toContain(payload.id);
|
||||
}
|
||||
const storedFailedUpdates = await page.evaluate(storeKey => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return JSON.parse(localStorage.getItem(storeKey) ?? '');
|
||||
}, storeKey);
|
||||
expect(storedFailedUpdates).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user