Skip to content

Commit

Permalink
test: add I18nProvider tests (QuiiBz#16)
Browse files Browse the repository at this point in the history
* test: add I18nProvider tests

* feat: add coverage

* test: add test for useI18n not inside I18nProvider

* test: enable getLocaleStaticProps test file

* test: add test for not defined locale within getLocaleStaticProps
  • Loading branch information
QuiiBz authored Jul 29, 2022
1 parent 65dd7ca commit 2634d0d
Show file tree
Hide file tree
Showing 9 changed files with 395 additions and 55 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ node_modules/
.next/
out/
dist/
coverage/

.DS_Store
*.log*
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"fixtures/*"
],
"scripts": {
"test": "vitest --run",
"test": "vitest --run --coverage",
"lint": "eslint --cache .",
"typecheck": "tsc --noEmit",
"prepare": "husky install"
Expand All @@ -26,6 +26,7 @@
"@typescript-eslint/eslint-plugin": "^5.26.0",
"@typescript-eslint/parser": "^5.26.0",
"@vitejs/plugin-react": "^2.0.0",
"c8": "^7.12.0",
"eslint": "^8.16.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { describe, expect, it, vi } from 'vitest';
import { createI18n } from '../src';
import en from './utils/en';

describe('getLocaleStaticProps', () => {
it('should error if locale is not defined', async () => {
const spy = vi.spyOn(console, 'error').mockImplementation(() => null);
const { getLocaleStaticProps } = createI18n<typeof import('./utils/en').default>({
en: () => import('./utils/en'),
fr: () => import('./utils/fr'),
});

const props = await getLocaleStaticProps()({
locales: ['en', 'fr'],
});

expect(props).toEqual({
props: {},
});
expect(console.error).toHaveBeenCalledWith(
"[next-international] 'i18n.defaultLocale' not defined in 'next.config.js'",
);
spy.mockReset();
});

it('should return default locale', async () => {
const { getLocaleStaticProps } = createI18n<typeof import('./utils/en').default>({
en: () => import('./utils/en'),
fr: () => import('./utils/fr'),
});

const props = await getLocaleStaticProps()({
locale: 'en',
defaultLocale: 'en',
locales: ['en', 'fr'],
});

expect(props).toEqual({
props: {
locale: en,
},
});
});

it('should return default locale with existing getStaticProps', async () => {
const { getLocaleStaticProps } = createI18n<typeof import('./utils/en').default>({
en: () => import('./utils/en'),
fr: () => import('./utils/fr'),
});

const props = await getLocaleStaticProps(() => ({
props: {
hello: 'world',
},
}))({
locale: 'en',
defaultLocale: 'en',
locales: ['en', 'fr'],
});

expect(props).toEqual({
props: {
hello: 'world',
locale: en,
},
});
});
});
52 changes: 0 additions & 52 deletions packages/next-international/__tests__/get-locale-static-props.ts

This file was deleted.

129 changes: 129 additions & 0 deletions packages/next-international/__tests__/i18n-provider.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import React from 'react';
import { describe, vi } from 'vitest';
import { createI18n } from '../src';
import { render, screen, waitFor } from './utils';
import en from './utils/en';

beforeEach(() => {
vi.mock('next/router', () => ({
useRouter: vi.fn().mockImplementation(() => ({
locale: 'en',
defaultLocale: 'en',
locales: ['en', 'fr'],
})),
}));
});

afterEach(() => {
vi.clearAllMocks();
});

describe('I18nProvider', () => {
describe('fallback', () => {
it('should return the fallback while loading the locale', async () => {
const { useI18n, I18nProvider } = createI18n<typeof import('./utils/en').default>({
en: () => import('./utils/en'),
fr: () => import('./utils/fr'),
});

function App() {
const { t } = useI18n();

return <p>{t('hello')}</p>;
}

render(
// @ts-expect-error we don't provide `locale` to test the fallback
<I18nProvider fallback={<p>Loading...</p>}>
<App />
</I18nProvider>,
);

expect(screen.getByText('Loading...')).toBeInTheDocument();

await waitFor(() => {
expect(screen.getByText('Hello')).toBeInTheDocument();
});
});

it('should return null if no fallback provided', async () => {
const { useI18n, I18nProvider } = createI18n<typeof import('./utils/en').default>({
en: () => import('./utils/en'),
fr: () => import('./utils/fr'),
});

function App() {
const { t } = useI18n();

return <p>{t('hello')}</p>;
}

render(
// @ts-expect-error we don't provide `locale` to test the fallback
<I18nProvider>
<App />
</I18nProvider>,
);

expect(screen.queryByText('Hello')).not.toBeInTheDocument();

await waitFor(() => {
expect(screen.getByText('Hello')).toBeInTheDocument();
});
});
});

describe('config', () => {
it('should warn about mismatching locales in createI18n', () => {
const spy = vi.spyOn(console, 'warn').mockImplementation(() => null);

const { useI18n, I18nProvider } = createI18n<typeof import('./utils/en').default>({
en: () => import('./utils/en'),
fr: () => import('./utils/fr'),
es: () => import('./utils/en'),
});

function App() {
const { t } = useI18n();

return <p>{t('hello')}</p>;
}

render(
<I18nProvider locale={en}>
<App />
</I18nProvider>,
);

expect(console.warn).toHaveBeenCalledWith(
"[next-international] The following locales are defined in 'createI18n' but not in 'next.config.js': es",
);
spy.mockClear();
});

it('should warn about mismatching locales in next.config.js', () => {
const spy = vi.spyOn(console, 'warn').mockImplementation(() => null);

const { useI18n, I18nProvider } = createI18n<typeof import('./utils/en').default>({
en: () => import('./utils/en'),
});

function App() {
const { t } = useI18n();

return <p>{t('hello')}</p>;
}

render(
<I18nProvider locale={en}>
<App />
</I18nProvider>,
);

expect(console.warn).toHaveBeenCalledWith(
"[next-international] The following locales are defined in 'next.config.js' but not in 'createI18n': fr",
);
spy.mockClear();
});
});
});
15 changes: 15 additions & 0 deletions packages/next-international/__tests__/use-i18n.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ afterEach(() => {
});

describe('useI18n', () => {
it('should thrown if not used inside I18nProvider', () => {
const { useI18n } = createI18n<typeof import('./utils/en').default>({
en: () => import('./utils/en'),
fr: () => import('./utils/fr'),
});

function App() {
const { t } = useI18n();

return <p>{t('hello')}</p>;
}

expect(() => render(<App />)).toThrowError('`useI18n` must be used inside `I18nProvider`');
});

it('should translate', async () => {
const { useI18n, I18nProvider } = createI18n<typeof import('./utils/en').default>({
en: () => import('./utils/en'),
Expand Down
1 change: 1 addition & 0 deletions packages/next-international/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { createI18n } from './i18n/create-i18n';
/* c8 ignore next */
export { BaseLocale, LocaleValue } from './types';
Loading

0 comments on commit 2634d0d

Please sign in to comment.