diff --git a/frontend/src/components/Trial/Trial.test.tsx b/frontend/src/components/Trial/Trial.test.tsx index 5c3b5667c..9db8e89e5 100644 --- a/frontend/src/components/Trial/Trial.test.tsx +++ b/frontend/src/components/Trial/Trial.test.tsx @@ -158,4 +158,67 @@ describe('Trial', () => { ); }); }); + + it("calls onResult when form is not defined", async () => { + const formless_feedback_form = { + ...feedback_form, + form: undefined + }; + render(); + fireEvent.click(screen.getByTestId('mock-feedback-form')); + await waitFor(() => { + expect(mockOnResult).toHaveBeenCalled(); + }); + }); + + it("calls onResult and onNext when form is not defined and break_round_on is met", async () => { + const formless_feedback_form = { + ...feedback_form, + form: undefined + }; + const config = { + ...defaultConfig, + break_round_on: { NOT: ['fast'] } + }; + render(); + fireEvent.click(screen.getByTestId('mock-feedback-form')); + await waitFor(() => { + expect(mockOnResult).toHaveBeenCalled(); + expect(mockOnNext).toHaveBeenCalled(); + }); + }); + + it("calls only onResult when form is not defined and break_round_on is NOT met", async () => { + const formless_feedback_form = { + ...feedback_form, + form: undefined + }; + const config = { + ...defaultConfig, + break_round_on: { EQUALS: ['slow'] } + }; + render(); + fireEvent.click(screen.getByTestId('mock-feedback-form')); + + await waitFor(() => { + expect(mockOnResult).toHaveBeenCalled(); + }); + + expect(mockOnNext).not.toHaveBeenCalled(); + }); }); diff --git a/frontend/src/components/Trial/Trial.tsx b/frontend/src/components/Trial/Trial.tsx index 37c041add..55cbc7d53 100644 --- a/frontend/src/components/Trial/Trial.tsx +++ b/frontend/src/components/Trial/Trial.tsx @@ -63,47 +63,15 @@ const Trial = (props: TrialProps) => { // Create result data const makeResult = useCallback( async (result: { type: 'time_passed' }) => { + // Prevent multiple submissions if (submitted.current) { return; } - submitted.current = true; - - // TODO: Check if we can find another solution for - // the default value of form than [{}] - const form = feedback_form ? feedback_form.form : [{}]; - - if (result.type === "time_passed") { - form.map((formElement) => (formElement.value = "TIMEOUT")); - } - - if (feedback_form) { - - if (feedback_form.is_skippable) { - form.map((formElement => (formElement.value = formElement.value || ''))) - } - - const breakRoundOn = config.break_round_on; - const shouldBreakRound = breakRoundOn && checkBreakRound(form.map((formElement) => formElement.value), breakRoundOn); - const shouldCallOnNextInOnResult = !shouldBreakRound - - await onResult( - { - decision_time: getAndStoreDecisionTime(), - form, - config - }, - false, - // if we break the round, we don't want to call onNext in onResult - shouldCallOnNextInOnResult - ); - - if (shouldBreakRound) { - onNext(true); - } - } else { + submitted.current = true; + if (!feedback_form) { if (result_id) { onResult({ @@ -114,18 +82,56 @@ const Trial = (props: TrialProps) => { onNext(); } + return; + } + + const { form = [] } = feedback_form; + + if (result.type === "time_passed") { + form.map((formElement) => (formElement.value = "TIMEOUT")); + } + + if (feedback_form.is_skippable) { + form.map((formElement => (formElement.value = formElement.value || ''))) } + + const breakRoundConditions = config.break_round_on; + const shouldBreakRound = breakRoundConditions && checkBreakRound(form.map((formElement) => formElement.value), breakRoundConditions); + + await onResult( + { + decision_time: getAndStoreDecisionTime(), + form, + config + }, + false, + // if we break the round, we don't want to call `onNext` in `onResult` + // as it does not allow us to pass a `breakRound` flag + !shouldBreakRound + ); + + if (shouldBreakRound) { + onNext(true); + } + }, [feedback_form, config, onNext, onResult, result_id] ); - const checkBreakRound = (values, breakConditions) => { + const checkBreakRound = ( + values: string[], + breakConditions: TrialConfig['break_round_on'] + ) => { switch (Object.keys(breakConditions)[0]) { case 'EQUALS': - return values.some(val => breakConditions['EQUALS'] - .includes(val)); + return values + .some( + val => breakConditions['EQUALS']!.includes(val) + ); case 'NOT': - return !values.some(val => breakConditions['NOT'].includes(val)); + return !values.some( + val => breakConditions['NOT']!.includes(val) + ); default: return false; } diff --git a/frontend/src/types/Trial.ts b/frontend/src/types/Trial.ts index f0e58c87b..32d21f190 100644 --- a/frontend/src/types/Trial.ts +++ b/frontend/src/types/Trial.ts @@ -1,3 +1,8 @@ +interface BreakRoundOn { + EQUALS?: string[]; + NOT?: string[]; +} + export interface TrialConfig { response_time: number; auto_advance: boolean; @@ -5,7 +10,7 @@ export interface TrialConfig { show_continue_button: boolean; continue_label: string; style: string; - break_round_on: any; + break_round_on: BreakRoundOn; auto_advance_timer: number | null; }