Skip to content

Commit

Permalink
feat: add autoplay functionality to media clips
Browse files Browse the repository at this point in the history
  • Loading branch information
weronika-szalas committed Dec 4, 2024
1 parent 54ab1d7 commit 03f7b45
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 34 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"storybook:build": "storybook build",
"storybook:static-serve": "storybook build --quiet && http-server ./storybook-static --port=6006",
"test": "jest --watch --collectCoverage=false",
"test:coverage": "jest --watch",
"test:coverage": "jest --silent --watch",
"test:ci": "jest",
"test:pages": "jest -c ./jest.pages.config.js ./src/__tests__",
"test:components": "jest -c ./jest.components.config.js ./src/components",
Expand Down Expand Up @@ -76,7 +76,7 @@
"@mdx-js/loader": "^3.1.0",
"@mux/mux-node": "^8.8.0",
"@mux/mux-player-react": "^3.1.0",
"@oaknational/oak-components": "^1.54.0",
"@oaknational/oak-components": "^1.55.0",
"@oaknational/oak-consent-client": "^2.1.1",
"@oaknational/oak-curriculum-schema": "^1.38.0",
"@oaknational/oak-pupil-client": "^2.12.3",
Expand Down
120 changes: 107 additions & 13 deletions src/components/TeacherViews/LessonMedia/LessonMedia.test.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { forwardRef } from "react";
import { useRouter } from "next/router";
import { within } from "@testing-library/dom";
import userEvent from "@testing-library/user-event";
Expand All @@ -18,6 +19,60 @@ jest.mock("next/router", () => ({
useRouter: jest.fn(),
}));

const currentErrorEvent = { detail: { data: { type: "networkError" } } };

jest.mock("@mux/mux-player-react/lazy", () => {
// @ts-expect-error - MuxPlayer mock
return forwardRef(({ onError, onPlay, onPause }, ref) => {
ref; // This prevents warning about ref not being used

return (
<div data-testid="mux-player">
<button
data-testid="error-button"
onClick={() => {
onError(currentErrorEvent);
}}
>
Error
</button>
<button data-testid="play-button" onClick={onPlay}>
Play
</button>
<button data-testid="pause-button" onClick={onPause}>
Pause
</button>
</div>
);
});
});

const localStorageMock = (() => {
let store = {} as Storage;

return {
getItem(key: string) {
return store[key];
},

setItem(key: string, value: string) {
store[key] = value;
},

removeItem(key: string) {
delete store[key];
},

clear() {
store = {} as Storage;
},
};
})();

Object.defineProperty(window, "sessionStorage", {
value: localStorageMock,
});

describe("LessonMedia view", () => {
jest.mock(
"@/components/TeacherComponents/helpers/lessonMediaHelpers/lessonMedia.helpers",
Expand All @@ -35,7 +90,7 @@ describe("LessonMedia view", () => {
pathname: "/test-path",
};
beforeEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
(useRouter as jest.Mock).mockReturnValue(mockRouter);
});

Expand All @@ -57,15 +112,6 @@ describe("LessonMedia view", () => {
);
});

it("renders media clip player", () => {
const { getByTestId } = render(
<LessonMedia lesson={lesson} isCanonical={false} />,
);

const mediaClipWrapper = getByTestId("media-clip-wrapper");
expect(mediaClipWrapper).toBeInTheDocument();
});

it("renders media clip player with correct amount of items", () => {
const { getByTestId } = render(
<LessonMedia lesson={lesson} isCanonical={false} />,
Expand All @@ -87,13 +133,13 @@ describe("LessonMedia view", () => {
const mediaClipWrapper = getByTestId("media-clip-wrapper");
const mediaClipList = within(mediaClipWrapper).getByRole("list");
const mediaClipListItems = within(mediaClipList).getAllByRole("listitem");
const mediaClipItem =
const videoItem =
mediaClipListItems[0] &&
within(mediaClipListItems[0]).getByRole("button");

if (mediaClipItem) {
if (videoItem) {
const user = userEvent.setup();
await user.click(mediaClipItem);
await user.click(videoItem);

expect(mockRouter.replace).toHaveBeenCalledTimes(1);
expect(mockRouter.replace).toHaveBeenCalledWith(
Expand All @@ -111,4 +157,52 @@ describe("LessonMedia view", () => {
);
}
});

it("calls router with correct parameters when audio is clicked", async () => {
const { getByTestId } = render(
<LessonMedia lesson={lesson} isCanonical={false} />,
);

const mediaClipWrapper = getByTestId("media-clip-wrapper");
const mediaClipList = within(mediaClipWrapper).getByRole("list");
const mediaClipListItems = within(mediaClipList).getAllByRole("listitem");
const audioItem =
mediaClipListItems[1] &&
within(mediaClipListItems[1]).getByRole("button");

if (audioItem) {
const user = userEvent.setup();
await user.click(audioItem);

expect(mockRouter.replace).toHaveBeenCalledTimes(1);
expect(mockRouter.replace).toHaveBeenCalledWith(
{
pathname: "/test-path",
query: {
lessonSlug: "running-as-a-team",
programmeSlug: "physical-education-ks4",
unitSlug: "running-and-jumping",
video: "running",
},
},
undefined,
{ shallow: true },
);
}
});

it("adds video slug to session storage when 'play' is pressed on the video", async () => {
const { getByTestId } = render(
<LessonMedia lesson={lesson} isCanonical={false} />,
);

const videoPlayerWrapper = getByTestId("video-player-wrapper");
const playButton = within(videoPlayerWrapper).getByText("Play");

await userEvent.click(playButton);

expect(sessionStorage.getItem("playedVideosList")).toBe(
"introduction-physical-exercise-video",
);
});
});
39 changes: 24 additions & 15 deletions src/components/TeacherViews/LessonMedia/LessonMedia.view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,34 +91,35 @@ export const LessonMedia = (props: LessonMediaProps) => {
const playedVideosList: string[] =
sessionStorage.getItem("playedVideosList")?.split(",") || [];

// action performed on media clip item click
const onMediaClipClick = (clipSlug: string) => {
const clickedMediaClip = listOfAllClips.find(
(clip) => clip.slug === clipSlug,
);

setCurrentClip(clickedMediaClip);
setCurrentIndex(
clickedMediaClip ? listOfAllClips.indexOf(clickedMediaClip) : 0,
);

// add video parameter to the url
const goToTheNextClip = (slug: string) =>
router.replace(
{
pathname: router.pathname,
query: {
programmeSlug: programmeSlug,
unitSlug: unitSlug,
lessonSlug: lessonSlug,
video: clipSlug,
video: slug,
},
},
undefined,
{ shallow: true },
);

// action performed on media clip item click
const onMediaClipClick = (clipSlug: string) => {
const clickedMediaClip = listOfAllClips.find(
(clip) => clip.slug === clipSlug,
);

setCurrentClip(clickedMediaClip);
setCurrentIndex(
clickedMediaClip ? listOfAllClips.indexOf(clickedMediaClip) : 0,
);
goToTheNextClip(clipSlug);
};

const handleVideoPlayed = (event: VideoEventCallbackArgs) => {
const handlePlayedVideo = (event: VideoEventCallbackArgs) => {
if (event.event === "play") {
if (currentClip && !playedVideosList.includes(currentClip?.slug)) {
// add played video to session storage
Expand All @@ -128,6 +129,12 @@ export const LessonMedia = (props: LessonMediaProps) => {
].toString();
sessionStorage.setItem("playedVideosList", updatedPlayedVideosList);
}
} else if (event.event === "end") {
const nextClip = listOfAllClips[currentIndex + 1];

if (nextClip) {
goToTheNextClip(nextClip.slug);
}
}
};

Expand All @@ -138,7 +145,7 @@ export const LessonMedia = (props: LessonMediaProps) => {
title={currentClip.mediaClipTitle}
location={"lesson"}
isLegacy={false}
userEventCallback={handleVideoPlayed}
userEventCallback={handlePlayedVideo}
/>
);

Expand Down Expand Up @@ -282,6 +289,8 @@ export const LessonMedia = (props: LessonMediaProps) => {
$background={"black"}
$overflow={["visible", "visible", "hidden"]}
$height={"100%"}
$br={"border-solid-m"}
data-testid="video-player-wrapper"
>
{videoPlayer}
</OakFlex>
Expand Down

0 comments on commit 03f7b45

Please sign in to comment.