Skip to content

Commit

Permalink
fix: add more test coverage + fix customDomain (#213)
Browse files Browse the repository at this point in the history
* test: add more test coverage

* test: more withNextVideo

* test: provider transformers

* test: add more test cov

* test: ignore some less risk files
  • Loading branch information
luwes authored Mar 28, 2024
1 parent cda7c06 commit c3e7aa1
Show file tree
Hide file tree
Showing 16 changed files with 366 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"status":"ready","originalFilePath":"https://storage.googleapis.com/muxdemofiles/mux.mp4","provider":"mux","providerMetadata":{"mux":{"assetId":"EploFGgmKULMpiyDFwsy5c6lmGcg8dkObaVvnPMcdkQ","playbackId":"jxEf6XiJs6JY017pSzpv8Hd6tTbdAOecHTq4FiFAn564"}},"createdAt":1710979438730,"updatedAt":1710979441038,"sources":[{"src":"https://stream.mux.com/.m3u8","type":"application/x-mpegURL"}],"poster":"https://image.mux.com//thumbnail.webp","blurDataURL":"data:image/webp;base64,UklGRlAAAABXRUJQVlA4IEQAAACwAQCdASoQAAkAAQAcJZwAAueBHFYwAP7+sPJ01xp5AM+XuhDsRQ67ZYXXhHDkrqsIkUGjQSCMuENc5y3Qg0o9pZgAAA=="}
{"status":"ready","originalFilePath":"https://storage.googleapis.com/muxdemofiles/mux.mp4","provider":"mux","providerMetadata":{"mux":{"assetId":"EploFGgmKULMpiyDFwsy5c6lmGcg8dkObaVvnPMcdkQ","playbackId":"jxEf6XiJs6JY017pSzpv8Hd6tTbdAOecHTq4FiFAn564"}},"createdAt":1710979438730,"updatedAt":1710979441038,"sources":[{"src":"https://stream.mux.com/jxEf6XiJs6JY017pSzpv8Hd6tTbdAOecHTq4FiFAn564.m3u8","type":"application/x-mpegURL"}],"poster":"https://image.mux.com//thumbnail.webp","blurDataURL":"data:image/webp;base64,UklGRlAAAABXRUJQVlA4IEQAAACwAQCdASoQAAkAAQAcJZwAAueBHFYwAP7+sPJ01xp5AM+XuhDsRQ67ZYXXhHDkrqsIkUGjQSCMuENc5y3Qg0o9pZgAAA=="}
5 changes: 3 additions & 2 deletions src/components/video.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import type { DefaultPlayerProps } from './players/default-player.js';
import type { Asset } from '../assets.js';
import type { VideoLoaderProps, VideoProps, VideoPropsInternal } from './types.js';

const DEV_MODE = process.env.NODE_ENV === 'development';

const NextVideo = forwardRef((props: VideoProps, forwardedRef) => {
// Keep in component so we can emulate the DEV_MODE.
const DEV_MODE = process.env.NODE_ENV === 'development';

let {
as: VideoPlayer = DefaultPlayer,
loader = defaultLoader,
Expand Down
2 changes: 2 additions & 0 deletions src/handlers/api-request.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* c8 ignore start */
import * as providers from '../providers/providers.js';
import { camelCase } from '../utils/utils.js';
import type { Asset } from '../assets.js';
Expand All @@ -10,3 +11,4 @@ export async function uploadRequestedFile(asset: Asset, config: HandlerConfig) {
}
}
}
/* c8 ignore stop */
5 changes: 4 additions & 1 deletion src/providers/mux/transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ export function transform(asset: Asset, props?: Props) {
const transformedAsset: Asset = {
...asset,

sources: [{ src: `https://stream.mux.com/${playbackId}.m3u8`, type: 'application/x-mpegURL' }],
sources: [{
src: `https://stream.${props?.customDomain ?? MUX_VIDEO_DOMAIN}/${playbackId}.m3u8`,
type: 'application/x-mpegURL'
}],

poster: getPosterURLFromPlaybackId(playbackId, {
thumbnailTime,
Expand Down
2 changes: 2 additions & 0 deletions src/utils/logger.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* c8 ignore start */
import chalk from 'chalk';

type logType = 'log' | 'error';
Expand Down Expand Up @@ -47,3 +48,4 @@ export default {
space,
label,
};
/* c8 ignore stop */
2 changes: 2 additions & 0 deletions src/utils/s3.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* c8 ignore start */
import {
S3Client,
PutBucketCorsCommand,
Expand Down Expand Up @@ -62,3 +63,4 @@ export function putBucketCors(s3: S3Client, bucketName: string) {
},
}));
}
/* c8 ignore stop */
24 changes: 24 additions & 0 deletions tests/components/alert.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import assert from 'node:assert';
import { test } from 'node:test';
import { setTimeout } from 'node:timers/promises';
import { create } from 'react-test-renderer';
import React from 'react';
import { Alert } from '../../src/components/alert.js';

test('renders an error alert', async () => {
const wrapper = create(<Alert status="error" hidden={true} />);
await setTimeout(50);
const fragment = wrapper.toJSON();
assert.equal(fragment[1].type, 'div');
assert.equal(fragment[1].props.className, 'next-video-alert next-video-alert-error');
assert.equal(fragment[1].props.hidden, true);
});

test('renders a sourced alert', async () => {
const wrapper = create(<Alert status="sourced" hidden={false} />);
await setTimeout(50);
const fragment = wrapper.toJSON();
assert.equal(fragment[1].type, 'div');
assert.equal(fragment[1].props.className, 'next-video-alert next-video-alert-sourced');
assert.equal(fragment[1].props.hidden, false);
});
24 changes: 24 additions & 0 deletions tests/components/utils.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import assert from 'node:assert';
import { test } from 'node:test';
import React from 'react';
import { isReactComponent, getUrlExtension } from '../../src/components/utils.js';

test('isReactComponent', () => {
assert.ok(isReactComponent(() => null), 'function component');
assert.ok(isReactComponent(class extends React.Component {}), 'class component');
assert.ok(isReactComponent(React.memo(() => null)), 'memo');
assert.ok(isReactComponent(React.forwardRef(() => null)), 'forwardRef');
});

test('getUrlExtension', () => {
assert.strictEqual(getUrlExtension('https://example.com/image.jpg'), 'jpg');
assert.strictEqual(getUrlExtension('https://example.com/image.jpg?foo=bar'), 'jpg');
assert.strictEqual(getUrlExtension('https://example.com/image.jpg#foo'), 'jpg');
assert.strictEqual(getUrlExtension('https://example.com/image.jpg?foo=bar#foo'), 'jpg');
assert.strictEqual(getUrlExtension('https://example.com/image.jpg?foo=bar&baz=qux'), 'jpg');
assert.strictEqual(getUrlExtension('https://example.com/image.jpg?foo=bar&baz=qux#foo'), 'jpg');
assert.strictEqual(getUrlExtension('https://example.com/image.jpg#foo?foo=bar&baz=qux'), 'jpg');
assert.strictEqual(getUrlExtension('https://example.com/image.jpg#foo?foo=bar&baz=qux#foo'), 'jpg');
assert.strictEqual(getUrlExtension('https://example.com/image.jpg?foo=bar&baz=qux#foo?foo=bar&baz=qux'), 'jpg');
assert.strictEqual(getUrlExtension('https://example.com/image.jpg?foo=bar&baz=qux#foo?foo=bar&baz=qux#foo'), 'jpg');
});
25 changes: 25 additions & 0 deletions tests/components/video-loader.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import assert from 'node:assert';
import { test, mock } from 'node:test';
import { defaultLoader, createVideoRequest } from '../../src/components/video-loader.js';

test('createVideoRequest', async () => {

mock.method(global, 'fetch', () => {
return { ok: true, status: 200, json: async () => ({ status: 'ready' }) };
});

const loader = ({ config, src, width, height }: any) => {
config.path = 'https://example.com/api/video';
return defaultLoader({ config, src, width, height });
};

const props = { src: 'https://example.com/video.mp4' };
const callback = (json) => {
assert.equal(json.status, 'ready');
};

const request = createVideoRequest(loader, props, callback);
await request(new AbortController().signal);

mock.reset();
});
60 changes: 59 additions & 1 deletion tests/components/video.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import assert from 'node:assert';
import { test } from 'node:test';
import { test, mock } from 'node:test';
import { setTimeout } from 'node:timers/promises';
import { create } from 'react-test-renderer';
import React from 'react';
Expand Down Expand Up @@ -36,3 +36,61 @@ test('renders mux-player with imported source', async () => {
'zNYmqdvJ61gt5uip02zPid01rYIPyyzVRVKQChgSgJlaY'
);
});

test('renders mux-player with string source', async () => {
await import('@mux/mux-player-react');

process.env.NODE_ENV = 'development';

let keepalive = globalThis.setTimeout(() => {}, 5_000);

let resolve;
const pollReady = new Promise((res) => {
resolve = res;
});

let count = 0;

mock.method(global, 'fetch', async () => {
return {
ok: true,
status: 200,
json: async () => {
count++;

if (count < 2) {
return {
status: 'uploading',
provider: 'mux',
};
}

resolve();

return {
status: 'ready',
provider: 'mux',
sources: [{
type: 'application/x-mpegURL',
src: 'https://stream.mux.com/jxEf6XiJs6JY017pSzpv8Hd6tTbdAOecHTq4FiFAn564.m3u8'
}]
};
}
};
});

const wrapper = create(<Video src="https://storage.googleapis.com/muxdemofiles/mux.mp4" />);

await pollReady;
await setTimeout(50);

clearTimeout(keepalive);

assert.equal(wrapper.toJSON().children[1].type, 'mux-player');
assert.equal(
wrapper.root.findByType('mux-player').parent.parent.props.src,
'https://stream.mux.com/jxEf6XiJs6JY017pSzpv8Hd6tTbdAOecHTq4FiFAn564.m3u8'
);

mock.reset();
});
28 changes: 28 additions & 0 deletions tests/providers/amazon-s3/transformer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import assert from 'node:assert';
import { test } from 'node:test';
import { transform } from '../../../src/providers/amazon-s3/transformer.js';
import type { Asset } from '../../../src/assets.js';

test('transform', async () => {
const asset: Asset = {
status: 'ready',
originalFilePath: '/videos/get-started.mp4',
createdAt: 0,
updatedAt: 0,
provider: 'amazon-s3',
providerMetadata: {
['amazon-s3']: {
endpoint: 'https://amazon-s3-url.com',
bucket: 'bucket',
key: 'key',
},
},
};

const transformedAsset = transform(asset);

assert.deepStrictEqual(transformedAsset, {
...asset,
sources: [{ src: 'https://bucket.amazon-s3-url.com/key' }],
});
});
28 changes: 28 additions & 0 deletions tests/providers/backblaze/transformer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import assert from 'node:assert';
import { test } from 'node:test';
import { transform } from '../../../src/providers/backblaze/transformer.js';
import type { Asset } from '../../../src/assets.js';

test('transform', async () => {
const asset: Asset = {
status: 'ready',
originalFilePath: '/videos/get-started.mp4',
createdAt: 0,
updatedAt: 0,
provider: 'backblaze',
providerMetadata: {
['backblaze']: {
endpoint: 'https://backblaze-url.com',
bucket: 'bucket',
key: 'key',
},
},
};

const transformedAsset = transform(asset);

assert.deepStrictEqual(transformedAsset, {
...asset,
sources: [{ src: 'https://bucket.backblaze-url.com/key' }],
});
});
31 changes: 31 additions & 0 deletions tests/providers/mux/transformer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import assert from 'node:assert';
import { test } from 'node:test';
import { transform } from '../../../src/providers/mux/transformer.js';
import type { Asset } from '../../../src/assets.js';

test('transform', async () => {
const asset: Asset = {
status: 'ready',
originalFilePath: '/videos/get-started.mp4',
createdAt: 0,
updatedAt: 0,
provider: 'mux',
providerMetadata: {
mux: {
playbackId: 'playbackId',
},
},
};

const transformedAsset = transform(asset, {
customDomain: 'custom-mux.com',
thumbnailTime: 20,
});

assert.deepStrictEqual(transformedAsset, {
...asset,
sources: [{ src: 'https://stream.custom-mux.com/playbackId.m3u8', type: 'application/x-mpegURL' }],
poster: 'https://image.custom-mux.com/playbackId/thumbnail.webp?time=20',
thumbnailTime: 20,
});
});
27 changes: 27 additions & 0 deletions tests/providers/vercel-blob/transformer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import assert from 'node:assert';
import { test } from 'node:test';
import { transform } from '../../../src/providers/vercel-blob/transformer.js';
import type { Asset } from '../../../src/assets.js';

test('transform', async () => {
const asset: Asset = {
status: 'ready',
originalFilePath: '/videos/get-started.mp4',
createdAt: 0,
updatedAt: 0,
provider: 'vercel-blob',
providerMetadata: {
['vercel-blob']: {
url: 'https://vercel-blob-url.com/get-started.mp4',
contentType: 'video/mp4',
},
},
};

const transformedAsset = transform(asset);

assert.deepStrictEqual(transformedAsset, {
...asset,
sources: [{ src: 'https://vercel-blob-url.com/get-started.mp4', type: 'video/mp4' }],
});
});
69 changes: 69 additions & 0 deletions tests/utils/provider.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import assert from 'node:assert';
import { test } from 'node:test';
import { setConfig } from 'next/config.js'
import { createAssetKey } from '../../src/utils/provider.js';

test('createAssetKey w/ defaultGenerateAssetKey and local asset', async () => {
setConfig({
serverRuntimeConfig: {
nextVideo: {
folder: 'videos',
providerConfig: {
'vercel-blob': {},
},
},
},
});

assert.equal(
await createAssetKey('/videos/get-started.mp4', 'vercel-blob'),
'/videos/get-started.mp4'
);

setConfig({});
});

test('createAssetKey w/ defaultGenerateAssetKey and remote asset', async () => {
setConfig({
serverRuntimeConfig: {
nextVideo: {
folder: 'videos',
providerConfig: {
'vercel-blob': {},
},
},
},
});

assert.equal(
await createAssetKey('https://storage.googleapis.com/muxdemofiles/mux.mp4', 'vercel-blob'),
'videos/mux.mp4'
);

setConfig({});
});

test('createAssetKey w/ custom generateAssetKey and remote asset', async () => {
setConfig({
serverRuntimeConfig: {
nextVideo: {
folder: 'videos',
providerConfig: {
'vercel-blob': {
generateAssetKey: (filePathOrURL, folder) => {
const url = new URL(filePathOrURL);
return `${folder}/remote${url.pathname}`;
},
},
},
},
},
});

assert.equal(
await createAssetKey('https://storage.googleapis.com/muxdemofiles/mux.mp4', 'vercel-blob'),
'videos/remote/muxdemofiles/mux.mp4'
);

setConfig({});
});
Loading

0 comments on commit c3e7aa1

Please sign in to comment.