diff --git a/client/src/redux/save-challenge-saga.js b/client/src/redux/save-challenge-saga.js index d412119e35a..f62c801246b 100644 --- a/client/src/redux/save-challenge-saga.js +++ b/client/src/redux/save-challenge-saga.js @@ -7,6 +7,7 @@ import { challengeDataSelector, challengeMetaSelector } from '../templates/Challenges/redux/selectors'; +import { createFiles } from '../templates/Challenges/redux/actions'; import { mapFilesToChallengeFiles, postSaveChallenge } from '../utils/ajax'; import { bodySizeFits, @@ -56,6 +57,7 @@ function* saveChallengeSaga() { if (data?.message) { yield put(createFlashMessage(data)); } else if (data?.savedChallenges) { + yield put(createFiles(challengeFiles)); yield put( saveChallengeComplete( mapFilesToChallengeFiles(data.savedChallenges) diff --git a/client/src/templates/Challenges/redux/actions.js b/client/src/templates/Challenges/redux/actions.js index 22c3bad958f..0386fb3d346 100644 --- a/client/src/templates/Challenges/redux/actions.js +++ b/client/src/templates/Challenges/redux/actions.js @@ -14,7 +14,7 @@ export const createFiles = createAction( challengeFile.editableRegionBoundaries ), seedEditableRegionBoundaries: - challengeFile.editableRegionBoundaries?.slice() + challengeFile.editableRegionBoundaries?.slice() ?? [] })) ); diff --git a/e2e/challenge-reset-modal.spec.ts b/e2e/challenge-reset-modal.spec.ts index f7b50572d05..c148c99597b 100644 --- a/e2e/challenge-reset-modal.spec.ts +++ b/e2e/challenge-reset-modal.spec.ts @@ -1,15 +1,11 @@ -import { test, expect } from '@playwright/test'; +import { execSync } from 'child_process'; + +import { test, expect, Page } from '@playwright/test'; import translations from '../client/i18n/locales/english/translations.json'; import { clearEditor, focusEditor, getEditors } from './utils/editor'; -test('should render the modal content correctly', async ({ page }) => { - await page.goto( - '/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-3' - ); - - await page.getByRole('button', { name: translations.buttons.reset }).click(); - +const expectToRenderResetModal = async (page: Page) => { await expect( page.getByRole('dialog', { name: translations.learn.reset }) ).toBeVisible(); @@ -35,6 +31,16 @@ test('should render the modal content correctly', async ({ page }) => { name: translations.buttons['reset-lesson'] }) ).toBeVisible(); +}; + +test('should render the modal content correctly', async ({ page }) => { + await page.goto( + '/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-3' + ); + + await page.getByRole('button', { name: translations.buttons.reset }).click(); + + await expectToRenderResetModal(page); }); test('User can reset challenge', async ({ page, isMobile, browserName }) => { @@ -154,41 +160,121 @@ test('should close when the user clicks the close button', async ({ page }) => { ).toBeHidden(); }); -test('User can reset on a multi-file project', async ({ page }) => { - { +test('User can reset on a multi-file project', async ({ + page, + isMobile, + browserName +}) => { + const sampleText = 'function palindrome() { return true; }'; + + await page.goto( + '/learn/javascript-algorithms-and-data-structures-v8/build-a-palindrome-checker-project/build-a-palindrome-checker' + ); + + await focusEditor({ page, isMobile }); + await clearEditor({ page, browserName }); + await getEditors(page).fill(sampleText); + await expect(page.getByText(sampleText)).toBeVisible(); + + await page.getByRole('button', { name: translations.buttons.reset }).click(); + + await expectToRenderResetModal(page); + + await page + .getByRole('button', { + name: translations.buttons['reset-lesson'] + }) + .click(); + + await expect(page.getByText(sampleText)).not.toBeVisible(); +}); + +test.describe('Signed in user', () => { + test.use({ storageState: 'playwright/.auth/development-user.json' }); + + test.beforeEach(() => { + execSync('node ./tools/scripts/seed/seed-demo-user'); + }); + + test.afterEach(() => { + execSync('node ./tools/scripts/seed/seed-demo-user certified-user'); + }); + + test('User can reset on a multi-file project after reloading and saving', async ({ + page, + isMobile, + browserName + }) => { + test.setTimeout(60000); + const savedText = 'function palindrome() { return true; }'; + const updatedText = 'function palindrome() { return false; }'; + await page.goto( '/learn/javascript-algorithms-and-data-structures-v8/build-a-palindrome-checker-project/build-a-palindrome-checker' ); + + // This first edit should reappear after the reset + await focusEditor({ page, isMobile }); + await clearEditor({ page, browserName }); + await getEditors(page).fill(savedText); + await page.keyboard.press('Control+S'); + + await page.reload(); + + // This second edit should be reset + await focusEditor({ page, isMobile }); + await clearEditor({ page, browserName }); + await getEditors(page).fill(updatedText); + await page .getByRole('button', { name: translations.buttons.reset }) .click(); - await expect( - page.getByRole('dialog', { name: translations.learn.reset }) - ).toBeVisible(); - - await expect( - page.getByRole('button', { - name: translations.buttons.close - }) - ).toBeVisible(); - await expect( - page.getByRole('heading', { - name: translations.learn.reset - }) - ).toBeVisible(); - - await expect( - page.getByText(translations.learn['reset-warn']) - ).toBeVisible(); - await expect( - page.getByText(translations.learn['reset-warn-2']) - ).toBeVisible(); - - await expect( - page.getByRole('button', { + await page + .getByRole('button', { name: translations.buttons['reset-lesson'] }) - ).toBeVisible(); - } + .click(); + + await expect(page.getByText(updatedText)).not.toBeVisible(); + await expect(page.getByText(savedText)).toBeVisible(); + }); + + test('User can reset on a multi-file project without reloading', async ({ + page, + isMobile, + browserName + }) => { + test.setTimeout(60000); + const savedText = 'function palindrome() { return true; }'; + const updatedText = 'function palindrome() { return false; }'; + + await page.goto( + '/learn/javascript-algorithms-and-data-structures-v8/build-a-palindrome-checker-project/build-a-palindrome-checker' + ); + + // This first edit should reappear after the reset + await focusEditor({ page, isMobile }); + await clearEditor({ page, browserName }); + await getEditors(page).fill(savedText); + await page.keyboard.press('Control+S'); + + // This second edit should be reset + await focusEditor({ page, isMobile }); + await clearEditor({ page, browserName }); + await getEditors(page).fill(updatedText); + + await page + .getByRole('button', { name: translations.buttons.reset }) + .click(); + + await page + .getByRole('button', { + name: translations.buttons['reset-lesson'] + }) + .click(); + + await expect(page.getByText(updatedText)).not.toBeVisible(); + await expect(page.getByText(savedText)).toBeVisible(); + }); });