Skip to content

Commit

Permalink
✨(website) creates lives on the website
Browse files Browse the repository at this point in the history
Give the possibility to create a live from the website.
  • Loading branch information
AntoLC committed Mar 22, 2023
1 parent d4ef93b commit 5ba1bbe
Show file tree
Hide file tree
Showing 9 changed files with 539 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Versioning](https://semver.org/spec/v2.0.0.html).
- standalone website:
- Integrate VOD dashboard (#2086)
- List the lives in the contents section (#2104)
- Create a live from the website (#2134)
- Add a License Manager widget for LTI VOD view
- Add a title to the classroom file dropzone
- Add can_edit property on a serialized video
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { render } from 'lib-tests';

import LiveCreate from './LiveCreate';

jest.mock('./LiveCreateForm', () => ({
__esModule: true,
default: () => <div>My LiveCreate Form</div>,
}));

describe('<LiveCreate />', () => {
test('renders LiveCreate', () => {
render(<LiveCreate />);

const button = screen.getByRole('button', { name: /Create Live/i });
expect(button).toBeInTheDocument();
expect(
screen.queryByRole('heading', { name: /Create Live/i }),
).not.toBeInTheDocument();

userEvent.click(button);

expect(
screen.getByRole('heading', { name: /Create Live/i }),
).toBeInTheDocument();
expect(screen.getByText('My LiveCreate Form')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Button, Heading, Text } from 'grommet';
import { useResponsive } from 'lib-components';
import { Fragment } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { Link, Route, Switch, useHistory } from 'react-router-dom';

import { WhiteCard } from 'components/Cards';
import { Modal } from 'components/Modal';
import { routes } from 'routes';

import LiveCreateForm from './LiveCreateForm';

const messages = defineMessages({
LiveTitle: {
defaultMessage: 'Lives',
description: 'Lives title',
id: 'features.Contents.features.Live.Create.LiveTitle',
},
CreateLiveLabel: {
defaultMessage: 'Create Live',
description: 'Text heading create live.',
id: 'features.Contents.features.Live.Create.CreateLiveLabel',
},
});

const LiveCreate = () => {
const intl = useIntl();
const { breakpoint } = useResponsive();
const history = useHistory();

const liveRoute = routes.CONTENTS.subRoutes.LIVE;
const livePath = liveRoute.path;
const liveCreatePath = liveRoute.subRoutes?.CREATE?.path || '';

return (
<Fragment>
<WhiteCard
flex="shrink"
direction={breakpoint === 'xxsmall' ? 'column' : 'row'}
gap={breakpoint === 'xxsmall' ? 'small' : 'none'}
justify="between"
align="center"
height={{ min: '5rem' }}
margin={{ bottom: 'medium' }}
>
<Text size="large" weight="bold">
{intl.formatMessage(messages.LiveTitle)}
</Text>
<Link to={liveCreatePath}>
<Button
primary
label={intl.formatMessage(messages.CreateLiveLabel)}
/>
</Link>
</WhiteCard>
<Switch>
<Route path={liveCreatePath} exact>
<Modal
isOpen
onClose={() => {
history.push(livePath);
}}
>
<Heading
level={2}
margin={{ top: 'xxsmall' }}
textAlign="center"
weight="bold"
>
{intl.formatMessage(messages.CreateLiveLabel)}
</Heading>
<LiveCreateForm />
</Modal>
</Route>
</Switch>
</Fragment>
);
};

export default LiveCreate;
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import { screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import fetchMock from 'fetch-mock';
import { createMemoryHistory } from 'history';
import { render, Deferred } from 'lib-tests';
import { Router } from 'react-router-dom';

import LiveCreateForm from './LiveCreateForm';

const playlistsResponse = {
count: 1,
next: null,
previous: null,
results: [
{ id: 'some-playlist-id', title: 'some playlist title' },
{ id: 'an-other-playlist', title: 'an other title' },
],
};

const consoleError = jest
.spyOn(console, 'error')
.mockImplementation(() => jest.fn());

let deferredPlaylists: Deferred<unknown>;
describe('<LiveCreateForm />', () => {
beforeEach(() => {
deferredPlaylists = new Deferred();
fetchMock.get(
'/api/playlists/?limit=20&offset=0&ordering=-created_on&can_edit=true',
deferredPlaylists.promise,
);
});

afterEach(() => {
fetchMock.restore();
jest.resetAllMocks();
consoleError.mockClear();
});

test('renders LiveCreateForm', async () => {
render(<LiveCreateForm />);

deferredPlaylists.resolve(playlistsResponse);

expect(screen.getByRole('textbox', { name: /title/i })).toBeInTheDocument();
expect(
await screen.findByRole('button', {
name: 'Choose the playlist.; Selected: some-playlist-id',
}),
).toBeInTheDocument();
expect(
screen.getByRole('textbox', { name: /description/i }),
).toBeInTheDocument();
expect(
screen.getByRole('button', { name: /Add Live/i }),
).toBeInTheDocument();
});

test('fields mandatory', async () => {
render(<LiveCreateForm />);

deferredPlaylists.resolve(playlistsResponse);

fireEvent.change(screen.getByRole('textbox', { name: /title/i }), {
target: { value: 'my title' },
});

userEvent.click(
await screen.findByRole('button', {
name: 'Choose the playlist.; Selected: some-playlist-id',
}),
);

userEvent.click(
await screen.findByRole('option', { name: 'an other title' }),
);

expect(
await screen.findByRole('button', {
name: 'Choose the playlist.; Selected: an-other-playlist',
}),
).toBeInTheDocument();

await waitFor(() =>
expect(
screen.getByRole('button', { name: /Add Live/i }),
).not.toBeDisabled(),
);
});

test('fields are posted correctly', async () => {
const history = createMemoryHistory();
fetchMock.post('/api/videos/', {
ok: true,
id: '1234',
});

fetchMock.mock(
'/api/videos/1234/initiate-live/',
{
ok: true,
id: '1234',
is_live: true,
},
{
method: 'POST',
},
);

render(
<Router history={history}>
<LiveCreateForm />
</Router>,
);

deferredPlaylists.resolve(playlistsResponse);

fireEvent.change(screen.getByRole('textbox', { name: /title/i }), {
target: { value: 'my title' },
});

fireEvent.change(screen.getByRole('textbox', { name: /description/i }), {
target: { value: 'my description' },
});

userEvent.click(
await screen.findByRole('button', {
name: 'Choose the playlist.; Selected: some-playlist-id',
}),
);

userEvent.click(
await screen.findByRole('option', { name: 'an other title' }),
);

expect(
await screen.findByRole('button', {
name: 'Choose the playlist.; Selected: an-other-playlist',
}),
).toBeInTheDocument();

const submit = screen.getByRole('button', { name: /Add Live/i });

await waitFor(() => expect(submit).not.toBeDisabled());

userEvent.click(submit);

await waitFor(() => {
expect(
fetchMock.lastCall('/api/videos/', {
method: 'POST',
})?.[1],
).toEqual({
headers: { 'Content-Type': 'application/json' },
method: 'POST',
body: JSON.stringify({
playlist: 'an-other-playlist',
title: 'my title',
live_type: 'jitsi',
description: 'my description',
}),
});
});

await waitFor(() => {
expect(history.location.pathname).toBe('/my-contents/lives/1234');
});
});

test('post failed', async () => {
fetchMock.post('/api/videos/', 500);

render(<LiveCreateForm />);

deferredPlaylists.resolve(playlistsResponse);

fireEvent.change(screen.getByRole('textbox', { name: /title/i }), {
target: { value: 'my title' },
});

fireEvent.change(screen.getByRole('textbox', { name: /description/i }), {
target: { value: 'my description' },
});

userEvent.click(
await screen.findByRole('button', {
name: 'Choose the playlist.; Selected: some-playlist-id',
}),
);

userEvent.click(
await screen.findByRole('option', { name: 'an other title' }),
);

expect(
await screen.findByRole('button', {
name: 'Choose the playlist.; Selected: an-other-playlist',
}),
).toBeInTheDocument();

const submit = screen.getByRole('button', { name: /Add Live/i });

await waitFor(() => expect(submit).not.toBeDisabled());

userEvent.click(submit);

expect(
await screen.findByText(
/Sorry, an error has occurred. Please try again./i,
),
).toBeInTheDocument();

expect(consoleError).toHaveBeenCalled();
});

test('error playlist', async () => {
render(<LiveCreateForm />);

deferredPlaylists.resolve(500);

expect(
await screen.findByText(
/Sorry, an error has occurred. Please try again./i,
),
).toBeInTheDocument();

expect(consoleError).toHaveBeenCalled();
});
});
Loading

0 comments on commit 5ba1bbe

Please sign in to comment.