Skip to content

Commit

Permalink
moved fireConfetti to execute-challenge-saga (#51938)
Browse files Browse the repository at this point in the history
  • Loading branch information
Riya267 committed Oct 27, 2023
1 parent ac8616e commit 941e18d
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,48 @@
import React from 'react';
import { runSaga } from 'redux-saga';
import { render } from '../../../../utils/test-utils';

import { getCompletedPercentage } from '../../../utils/get-completion-percentage';
import { fireConfetti } from '../../../utils/fire-confetti';
import { createStore } from '../../../redux/create-store';
import { executeChallengeSaga } from '../redux/execute-challenge-saga';
import {
challengeDataSelector,
challengeMetaSelector,
challengeTestsSelector,
isBuildEnabledSelector,
isBlockNewlyCompletedSelector
} from '../redux/selectors';
import { buildChallenge, getTestRunner } from '../utils/build';
import CompletionModal from './completion-modal';

jest.mock('../../../analytics');
jest.mock('../../../utils/fire-confetti');
jest.mock('../../../components/ProgressBar');
jest.mock('../redux/selectors');
jest.mock('../utils/build');
const mockFireConfetti = fireConfetti as jest.Mock;
const mockTestRunner = jest.fn().mockReturnValue({ pass: true });
const mockBuildEnabledSelector = isBuildEnabledSelector as jest.Mock;
const mockChallengeTestsSelector = challengeTestsSelector as jest.Mock;
const mockChallengeMetaSelector = challengeMetaSelector as jest.Mock;
const mockChallengeDataSelector = challengeDataSelector as jest.Mock;
const mockIsBlockNewlyCompletedSelector =
isBlockNewlyCompletedSelector as jest.Mock;
const mockBuildChallenge = buildChallenge as jest.Mock;
const mockGetTestRunner = getTestRunner as jest.Mock;
mockBuildEnabledSelector.mockReturnValue(true);
mockChallengeTestsSelector.mockReturnValue([
{ text: 'Test 1', testString: 'mock test code' }
]);
mockChallengeMetaSelector.mockReturnValue({
challengeType: 'mock_challenge_type'
});
mockChallengeDataSelector.mockReturnValue({
challengeFiles: ['mock_challenge_files']
});
mockBuildChallenge.mockReturnValue({ challengeType: 'mock_challenge_type' });
mockGetTestRunner.mockReturnValue(mockTestRunner);

const completedChallengesIds = ['1', '3', '5'],
currentBlockIds = ['1', '3', '5', '7'],
Expand All @@ -21,7 +54,41 @@ describe('<CompletionModal />', () => {
beforeEach(() => {
mockFireConfetti.mockClear();
});
test('should fire if certification project has been completed', () => {
test('should fire when block is completed', async () => {
const payload = { showCompletionModal: true };
const store = createStore({
challenge: {
modal: { completion: true },
challengeMeta: {
id: 'bd7158d8c442eddfaeb5bd18',
certification: 'responsive-web-design' // Make sure the certification matches
}
}
});
mockIsBlockNewlyCompletedSelector.mockReturnValue(true);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
await runSaga(store, executeChallengeSaga, { payload }).done;
expect(mockFireConfetti).toHaveBeenCalledTimes(1);
});
test('should not fire when block is not completed', async () => {
const payload = { showCompletionModal: true };
const store = createStore({
challenge: {
modal: { completion: true },
challengeMeta: {
id: 'bd7158d8c442eddfaeb5bd18',
certification: 'responsive-web-design' // Make sure the certification matches
}
}
});
mockIsBlockNewlyCompletedSelector.mockReturnValue(false);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
await runSaga(store, executeChallengeSaga, { payload }).done;
expect(mockFireConfetti).toHaveBeenCalledTimes(0);
});
test('should not fire if certification project has been completed', () => {
const store = createStore({
challenge: {
modal: { completion: true },
Expand All @@ -31,12 +98,10 @@ describe('<CompletionModal />', () => {
}
}
});

render(<CompletionModal />, store);

expect(mockFireConfetti).toHaveBeenCalledTimes(1);
expect(mockFireConfetti).toHaveBeenCalledTimes(0);
});

test('should NOT fire if the challenge is not a project', () => {
const store = createStore({
challenge: {
Expand Down
19 changes: 2 additions & 17 deletions client/src/templates/Challenges/components/completion-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ import ProgressBar from '../../../components/ProgressBar';
import GreenPass from '../../../assets/icons/green-pass';

import './completion-modal.css';
import { fireConfetti } from '../../../utils/fire-confetti';
import { certsToProjects } from '../../../../config/cert-and-project-map';

const mapStateToProps = createSelector(
challengeFilesSelector,
Expand Down Expand Up @@ -81,11 +79,6 @@ interface CompletionModalState {
downloadURL: null | string;
}

const isCertificationProject = (id: string) =>
Object.values(certsToProjects).some(cert =>
cert.some(project => project.id === id)
);

class CompletionModal extends Component<
CompletionModalsProps,
CompletionModalState
Expand Down Expand Up @@ -157,26 +150,18 @@ class CompletionModal extends Component<
const {
close,
isOpen,
id,
isSignedIn,
isSubmitting,
message,
t,
dashedName,
submitChallenge,
completedChallengesIds
submitChallenge
} = this.props;

if (isOpen) {
executeGA({ event: 'pageview', pagePath: '/completion-modal' });
if (
isCertificationProject(id) &&
!completedChallengesIds.includes(id) &&
!isSubmitting
) {
fireConfetti();
}
}

return (
<Modal
data-cy='completion-modal'
Expand Down
11 changes: 9 additions & 2 deletions client/src/templates/Challenges/redux/execute-challenge-saga.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
} from '../utils/build';
import { runPythonInFrame, mainPreviewId } from '../utils/frame';
import { executeGA } from '../../../redux/actions';
import { fireConfetti } from '../../../utils/fire-confetti';
import { actionTypes } from './action-types';
import {
disableBuildOnError,
Expand All @@ -53,7 +54,8 @@ import {
challengeTestsSelector,
isBuildEnabledSelector,
isExecutingSelector,
portalDocumentSelector
portalDocumentSelector,
isBlockNewlyCompletedSelector
} from './selectors';

// How long before bailing out of a preview.
Expand Down Expand Up @@ -87,7 +89,7 @@ function* executeCancellableChallengeSaga(payload) {
yield cancel(task);
}

function* executeChallengeSaga({ payload }) {
export function* executeChallengeSaga({ payload }) {
const isBuildEnabled = yield select(isBuildEnabledSelector);
if (!isBuildEnabled) {
return;
Expand Down Expand Up @@ -126,8 +128,12 @@ function* executeChallengeSaga({ payload }) {
yield put(updateTests(testResults));

const challengeComplete = testResults.every(test => test.pass && !test.err);
const isBlockCompleted = yield select(isBlockNewlyCompletedSelector);
if (challengeComplete) {
playTone('tests-completed');
if (isBlockCompleted) {
fireConfetti();
}
} else {
playTone('tests-failed');
if (challengeMeta.certification === 'responsive-web-design') {
Expand All @@ -141,6 +147,7 @@ function* executeChallengeSaga({ payload }) {
);
}
}

if (challengeComplete && payload?.showCompletionModal) {
yield put(openModal('completion'));
}
Expand Down

0 comments on commit 941e18d

Please sign in to comment.