diff --git a/client/src/redux/prop-types.ts b/client/src/redux/prop-types.ts index be0db623874..e349ceef89a 100644 --- a/client/src/redux/prop-types.ts +++ b/client/src/redux/prop-types.ts @@ -172,6 +172,7 @@ export type ChallengeNode = { head: string[]; hasEditableBoundaries: boolean; helpCategory: string; + hooks?: { beforeAll: string }; id: string; instructions: string; isComingSoon: boolean; diff --git a/client/src/templates/Challenges/classic/show.tsx b/client/src/templates/Challenges/classic/show.tsx index 5c71f40b7aa..c8baf9a856d 100644 --- a/client/src/templates/Challenges/classic/show.tsx +++ b/client/src/templates/Challenges/classic/show.tsx @@ -45,6 +45,7 @@ import { executeChallenge, initConsole, initTests, + initHooks, initVisibleEditors, previewMounted, updateChallengeMeta, @@ -86,6 +87,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => createFiles, initConsole, initTests, + initHooks, initVisibleEditors, updateChallengeMeta, challengeMounted, @@ -108,6 +110,7 @@ interface ShowClassicProps extends Pick { challengeFiles: ChallengeFiles; initConsole: (arg0: string) => void; initTests: (tests: Test[]) => void; + initHooks: (hooks?: { beforeAll: string }) => void; initVisibleEditors: () => void; isChallengeCompleted: boolean; output: string[]; @@ -193,6 +196,7 @@ function ShowClassic({ title, description, instructions, + hooks, fields: { tests, blockName }, challengeType, hasEditableBoundaries, @@ -216,6 +220,7 @@ function ShowClassic({ challengeMounted, initConsole, initTests, + initHooks, initVisibleEditors, updateChallengeMeta, openModal, @@ -359,6 +364,7 @@ function ShowClassic({ ); initTests(tests); + initHooks(hooks); initVisibleEditors(); @@ -556,6 +562,9 @@ export const query = graphql` superBlock translationPending forumTopicId + hooks { + beforeAll + } fields { blockName slug diff --git a/client/src/templates/Challenges/redux/action-types.js b/client/src/templates/Challenges/redux/action-types.js index d9d2efd3fea..a988ea8bdee 100644 --- a/client/src/templates/Challenges/redux/action-types.js +++ b/client/src/templates/Challenges/redux/action-types.js @@ -8,6 +8,7 @@ export const actionTypes = createTypes( [ 'createFiles', 'createQuestion', + 'initHooks', 'initTests', 'initConsole', 'initLogs', diff --git a/client/src/templates/Challenges/redux/actions.js b/client/src/templates/Challenges/redux/actions.js index 7ccb65f257f..39970babac0 100644 --- a/client/src/templates/Challenges/redux/actions.js +++ b/client/src/templates/Challenges/redux/actions.js @@ -22,6 +22,7 @@ export const createFiles = createAction( export const createQuestion = createAction(actionTypes.createQuestion); export const initTests = createAction(actionTypes.initTests); +export const initHooks = createAction(actionTypes.initHooks); export const updateTests = createAction(actionTypes.updateTests); export const cancelTests = createAction(actionTypes.cancelTests); export const initConsole = createAction(actionTypes.initConsole); diff --git a/client/src/templates/Challenges/redux/execute-challenge-saga.js b/client/src/templates/Challenges/redux/execute-challenge-saga.js index 9514a4a3290..4e51f880c41 100644 --- a/client/src/templates/Challenges/redux/execute-challenge-saga.js +++ b/client/src/templates/Challenges/redux/execute-challenge-saga.js @@ -55,6 +55,7 @@ import { challengeDataSelector, challengeMetaSelector, challengeTestsSelector, + challengeHooksSelector, isBuildEnabledSelector, isExecutingSelector, portalDocumentSelector, @@ -110,6 +111,7 @@ export function* executeChallengeSaga({ payload }) { const tests = (yield select(challengeTestsSelector)).map( ({ text, testString }) => ({ text, testString }) ); + const hooks = yield select(challengeHooksSelector); yield put(updateTests(tests)); yield fork(takeEveryLog, consoleProxy); @@ -128,7 +130,7 @@ export function* executeChallengeSaga({ payload }) { const document = yield getContext('document'); const testRunner = yield call( getTestRunner, - buildData, + { ...buildData, hooks }, { proxyLogger }, document ); diff --git a/client/src/templates/Challenges/redux/index.js b/client/src/templates/Challenges/redux/index.js index a24ffab0d3a..b24916a75bb 100644 --- a/client/src/templates/Challenges/redux/index.js +++ b/client/src/templates/Challenges/redux/index.js @@ -120,6 +120,10 @@ export const reducer = handleActions( ...state, challengeTests: payload }), + [actionTypes.initHooks]: (state, { payload }) => ({ + ...state, + challengeHooks: payload + }), [actionTypes.updateTests]: (state, { payload }) => ({ ...state, challengeTests: payload diff --git a/client/src/templates/Challenges/redux/selectors.js b/client/src/templates/Challenges/redux/selectors.js index 437630d1fcb..0c3d82972ca 100644 --- a/client/src/templates/Challenges/redux/selectors.js +++ b/client/src/templates/Challenges/redux/selectors.js @@ -14,6 +14,7 @@ import { ns } from './action-types'; export const challengeFilesSelector = state => state[ns].challengeFiles; export const challengeMetaSelector = state => state[ns].challengeMeta; +export const challengeHooksSelector = state => state[ns].challengeHooks; export const challengeTestsSelector = state => state[ns].challengeTests; export const consoleOutputSelector = state => state[ns].consoleOut; export const completedChallengesIdsSelector = createSelector( diff --git a/client/src/templates/Challenges/utils/frame.ts b/client/src/templates/Challenges/utils/frame.ts index 6c8d4d0eb54..090841425ee 100644 --- a/client/src/templates/Challenges/utils/frame.ts +++ b/client/src/templates/Challenges/utils/frame.ts @@ -16,6 +16,10 @@ export interface Source { original: { [key: string]: string | null }; } +interface Hooks { + beforeAll?: string; +} + export interface Context { window?: Window & typeof globalThis & { i18nContent?: i18n; __pyodide: unknown }; @@ -23,6 +27,7 @@ export interface Context { element: HTMLIFrameElement; build: string; sources: Source; + hooks?: Hooks; loadEnzyme?: () => void; } @@ -89,7 +94,7 @@ const DOCUMENT_NOT_FOUND_ERROR = 'misc.document-notfound'; // The "fcc-hide-header" class on line 95 is added to ensure that the CSSHelper class ignores this style element // during tests, preventing CSS-related test failures. -export const createHeader = (id = mainPreviewId) => +const createHeader = (id = mainPreviewId) => `