Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/lang/locales/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@
"error": {
"unknown": "Es ist ein unbekannter Fehler aufgetreten.",
"image": "Laden des Bildes fehlgeschlagen",
"not-found": "Die von dir gesuchte Seite wurde nicht gefunden."
"not-found": "Die von dir gesuchte Seite wurde nicht gefunden.",
"back-to-documentation": "Zurück zur Dokumentation"
},
"color-scheme": {
"select": "Bevorzugtes Farbschema auswählen",
Expand Down
3 changes: 2 additions & 1 deletion src/lang/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@
"error": {
"unknown": "An unknown error occurred.",
"image": "Image failed to load",
"not-found": "The page you're looking for can't be found."
"not-found": "The page you're looking for can't be found.",
"back-to-documentation": "Back to Documentation"
},
"color-scheme": {
"select": "Select a color scheme preference",
Expand Down
3 changes: 2 additions & 1 deletion src/lang/locales/es-419.json
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@
"error": {
"unknown": "Ocurrió un error desconocido.",
"image": "Error al cargar la imagen",
"not-found": "No se encuentra la página que buscas."
"not-found": "No se encuentra la página que buscas.",
"back-to-documentation": "Volver a la documentación"
},
"color-scheme": {
"select": "Selecciona el esquema de colores que prefieras",
Expand Down
3 changes: 2 additions & 1 deletion src/lang/locales/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@
"error": {
"unknown": "Une erreur inconnue est survenue.",
"image": "Échec du chargement de l'image",
"not-found": "La page que vous recherchez est introuvable."
"not-found": "La page que vous recherchez est introuvable.",
"back-to-documentation": "Retour à la documentation"
},
"color-scheme": {
"select": "Sélectionnez une préférence de palette de couleurs",
Expand Down
3 changes: 2 additions & 1 deletion src/lang/locales/it-IT.json
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@
"error": {
"unknown": "Si è verificato un errore sconosciuto.",
"image": "Impossibile caricare l'immagine",
"not-found": "La pagina richiesta non è stata trovata."
"not-found": "La pagina richiesta non è stata trovata.",
"back-to-documentation": "Torna alla documentazione"
},
"color-scheme": {
"select": "Seleziona una preferenza per lo schema colore",
Expand Down
3 changes: 2 additions & 1 deletion src/lang/locales/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@
"error": {
"unknown": "原因不明のエラーが起きました。",
"image": "イメージを読み込めませんでした",
"not-found": "探しているページが見つかりません。"
"not-found": "探しているページが見つかりません。",
"back-to-documentation": "ドキュメントに戻る"
},
"color-scheme": {
"select": "カラースキーム環境設定を選択",
Expand Down
3 changes: 2 additions & 1 deletion src/lang/locales/ko-KR.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@
"error": {
"unknown": "알 수 없는 오류가 발생했습니다.",
"image": "이미지를 로드하는 데 실패함",
"not-found": "해당 페이지를 찾을 수 없습니다."
"not-found": "해당 페이지를 찾을 수 없습니다.",
"back-to-documentation": "문서로 돌아가기"
},
"color-scheme": {
"select": "색상 모드 환경설정 선택",
Expand Down
3 changes: 2 additions & 1 deletion src/lang/locales/pt-BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@
"error": {
"unknown": "Ocorreu um erro desconhecido.",
"image": "Falha ao carregar a imagem",
"not-found": "Não é possível encontrar a página que você procura."
"not-found": "Não é possível encontrar a página que você procura.",
"back-to-documentation": "Voltar para a documentação"
},
"color-scheme": {
"select": "Selecione uma preferência de esquema de cores",
Expand Down
3 changes: 2 additions & 1 deletion src/lang/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@
"error": {
"unknown": "出现未知错误。",
"image": "图像无法载入",
"not-found": "找不到你所查找的页面。"
"not-found": "找不到你所查找的页面。",
"back-to-documentation": "返回文档"
},
"color-scheme": {
"select": "选择首选颜色方案",
Expand Down
44 changes: 42 additions & 2 deletions src/views/NotFound.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,53 @@

<template>
<GenericError :message="$t('error.not-found')">
<div v-if="documentationLink" class="back-link-container">
<Reference :url="documentationLink">
{{ $t('error.back-to-documentation') }}
</Reference>
</div>
<slot />
</GenericError>
</template>

<script>
import { updateLocale } from 'theme/utils/i18n-utils';
import GenericError from 'theme/components/GenericError.vue';
import Reference from 'docc-render/components/ContentNode/Reference.vue';
import { fetchData } from 'docc-render/utils/data';
import { pathJoin } from 'docc-render/utils/assets';
import AppStore from 'docc-render/stores/AppStore';

export default {
name: 'NotFound',
components: { GenericError },
created() {
components: { GenericError, Reference },
data() {
return {
documentationPath: null,
};
},
computed: {
documentationLink() {
return this.documentationPath;
},
},
async created() {
AppStore.setAllLocalesAreAvailable();
try {
const slug = this.$route?.params?.locale || '';
const path = pathJoin(['/index/', slug, 'index.json']);
const { interfaceLanguages = {} } = await fetchData(path);

const firstModule = Object.values(interfaceLanguages)
.map(items => items.find(item => item.type === 'module'))
.find(Boolean);

if (firstModule) {
this.documentationPath = firstModule.path;
}
} catch (e) {
// Link won't render if fetch fails
}
},
beforeRouteEnter(to, from, next) {
next((vm) => {
Expand All @@ -35,3 +68,10 @@ export default {
},
};
</script>

<style lang="scss" scoped>
.back-link-container {
text-align: center;
margin-top: 32px;
}
</style>
56 changes: 55 additions & 1 deletion tests/unit/views/NotFound.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,77 @@

import NotFound from 'docc-render/views/NotFound.vue';
import { shallowMount } from '@vue/test-utils';
import Language from 'docc-render/constants/Language';
import { fetchData } from 'docc-render/utils/data';
import { flushPromises } from '../../../test-utils';

const { GenericError } = NotFound.components;
jest.mock('docc-render/utils/data');

const { GenericError, Reference } = NotFound.components;

describe('NotFound', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('renders a `GenericError` with a custom message', () => {
fetchData.mockResolvedValue({ interfaceLanguages: {} });
const wrapper = shallowMount(NotFound);
const error = wrapper.findComponent(GenericError);
expect(error.exists()).toBe(true);
expect(error.props('message')).toBe('error.not-found');
});

it('exposes a default slot', () => {
fetchData.mockResolvedValue({ interfaceLanguages: {} });
const wrapper = shallowMount(NotFound, {
slots: {
default: '<div class="default">Default Content</div>',
},
});
expect(wrapper.findComponent('.default').text()).toBe('Default Content');
});

it('renders the back link when a module is found', async () => {
fetchData.mockResolvedValue({
interfaceLanguages: {
[Language.swift.key.url]: [{ type: 'module', path: '/documentation/swift' }],
},
});
const wrapper = shallowMount(NotFound);
await flushPromises();
const backLink = wrapper.findComponent(Reference);
expect(backLink.exists()).toBe(true);
expect(backLink.props('url')).toBe('/documentation/swift');
});

it('does not render the back link when no module is found', async () => {
fetchData.mockResolvedValue({
interfaceLanguages: { [Language.swift.key.url]: [] },
});
const wrapper = shallowMount(NotFound);
await flushPromises();
expect(wrapper.findComponent(Reference).exists()).toBe(false);
});

it('does not render the back link when index fetch fails', async () => {
fetchData.mockRejectedValue(new Error('Fetch failed'));
const wrapper = shallowMount(NotFound);
await flushPromises();
expect(wrapper.findComponent(Reference).exists()).toBe(false);
});

it('uses the first module found across interface languages', async () => {
fetchData.mockResolvedValue({
interfaceLanguages: {
[Language.objectiveC.key.url]: [{ type: 'something-else' }],
[Language.swift.key.url]: [{ type: 'module', path: '/documentation/swift' }],
},
});
const wrapper = shallowMount(NotFound);
await flushPromises();
const backLink = wrapper.findComponent(Reference);
expect(backLink.exists()).toBe(true);
expect(backLink.props('url')).toBe('/documentation/swift');
});
});