Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ describe("Test for occupationGroup PATCH handler with a DB", () => {
});
const givenOccupationGroup = await getRepositoryRegistry().OccupationGroup.create({
...getNewISCOGroupSpecsWithoutImportId(),
// A fixed origin URI, as the random one has no scheme in some runs and then fails the response schema's uri format.
originUri: "https://example.com/managers",
modelId: givenModel.id,
preferredLabel: { en: "Managers", fr: "Directeurs" },
description: { en: "A description", fr: "Une description" },
Expand Down
9 changes: 6 additions & 3 deletions frontend/.storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import "../src/styles/variables.css"
import type { Preview } from "@storybook/react";
import CustomSnackbarProvider from "../src/theme/SnackbarProvider/SnackbarProvider";
import { IsOnlineProvider, QueryProvider } from "../src/app/providers";
import { LanguageProvider } from "../src/language/LanguageProvider";
import { AuthContext, authContextDefaultValue } from "../src/auth/AuthProvider";
import { applyBrandingFromEnv } from "../src/branding/branding";

Expand Down Expand Up @@ -86,9 +87,11 @@ export const decorators = [
<CustomSnackbarProvider>
<AuthContext.Provider value={authContextValue}>
<QueryProvider>
<div style={{ height: "100vh" }}>
<Story />
</div>
<LanguageProvider>
<div style={{ height: "100vh" }}>
<Story />
</div>
</LanguageProvider>
</QueryProvider>
</AuthContext.Provider>
</CustomSnackbarProvider>
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/_test_utilities/test-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ import applicationTheme, { ThemeMode } from "src/theme/applicationTheme/applicat
import SnackbarProvider from "src/theme/SnackbarProvider/SnackbarProvider";
import { IsOnlineProvider, QueryProvider } from "src/app/providers";
import { AuthProvider } from "src/auth/AuthProvider";
import { LanguageProvider } from "src/language/LanguageProvider";

const AllTheProviders = ({ children }: { children: React.ReactNode }) => {
return (
<IsOnlineProvider>
<ThemeProvider theme={applicationTheme(ThemeMode.LIGHT)}>
<AuthProvider>
<SnackbarProvider>
<QueryProvider>{children}</QueryProvider>
<QueryProvider>
<LanguageProvider>{children}</LanguageProvider>
</QueryProvider>
</SnackbarProvider>
</AuthProvider>
</ThemeProvider>
Expand Down
108 changes: 106 additions & 2 deletions frontend/src/explorer/ExplorerPage.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import type { Meta, StoryObj } from "@storybook/react";
import React from "react";
import { Routes, Route } from "react-router-dom";
import ExplorerPage from "./ExplorerPage";
import { Routes, Route, useSearchParams } from "react-router-dom";
import LanguageAPISpecs from "api-specifications/language";
import ExplorerPage, { LANGUAGE_QUERY_PARAM } from "./ExplorerPage";
import { DATA_TEST_ID as TREE_PANEL_DATA_TEST_ID } from "src/explorer/components/ExplorerTreePanel/ExplorerTreePanel";
import * as MockPayload from "src/modelInfo/_test_utilities/mockModelInfoPayload";
import { ObjectType } from "src/explorer/explorer.types";
import { getApiUrl } from "src/envService";
import { routerPaths } from "src/app/routerPaths";
import { DEFAULT_LANGUAGE } from "src/language/languages.service";

const MODELS_URL = getApiUrl() + "/models";

Expand Down Expand Up @@ -231,3 +233,105 @@ export const Skills: Story = {
</Routes>
),
};

// --- Multilingual model ---
const multilingualModels = MockPayload.GET.getPayloadWithOneMultilingualModelInfo();
const multilingualModelUrl = `${getApiUrl()}/models/${multilingualModels[0].id}`;

const multilingualTexts: Record<string, { group: string; occupation: string; definition: string; skill: string }> = {
en: {
group: "Managers",
occupation: "Business services managers",
definition: "Business services managers plan, direct and coordinate the delivery of business services.",
skill: "manage budgets",
},
fr: {
group: "Directeurs et cadres de direction",
occupation: "Directeurs des services aux entreprises",
definition:
"Les directeurs des services aux entreprises planifient, dirigent et coordonnent la prestation de services.",
skill: "gérer des budgets",
},
es: {
group: "Directores y gerentes",
occupation: "Directores de servicios empresariales",
definition: "Los directores de servicios empresariales planifican, dirigen y coordinan la prestación de servicios.",
skill: "gestionar presupuestos",
},
};

// The mock addon does not pass the request headers to a response function, so the Accept-Language sent by the
// explorer cannot be read there. The selected language is captured from the URL instead: the explorer requests the
// language of the URL from the very first render, while the language context only catches up once the models load,
// which would answer the first requests in the wrong language and cache that answer.
let selectedLanguage = DEFAULT_LANGUAGE;
const CaptureSelectedLanguage = ({ children }: { children: React.ReactNode }) => {
const [searchParams] = useSearchParams();
const urlLanguage = searchParams.get(LANGUAGE_QUERY_PARAM);
selectedLanguage =
urlLanguage !== null && LanguageAPISpecs.Helpers.isSupportedLanguage(urlLanguage) ? urlLanguage : DEFAULT_LANGUAGE;
return <>{children}</>;
};
const texts = () => multilingualTexts[selectedLanguage] ?? multilingualTexts[DEFAULT_LANGUAGE];

const multilingualGroup = () => ({
id: "grp-1",
UUID: "grp-1-uuid",
code: "1",
preferredLabel: texts().group,
altLabels: [],
groupType: ObjectType.ISCOGroup,
children: [
{ id: "occ-1120", code: "1120", preferredLabel: texts().occupation, objectType: ObjectType.ESCOOccupation },
],
});

// Opens on an occupation in French. Switch the language from the header to see the taxonomy's data change.
export const MultilingualModel: Story = {
decorators: [
(Story) => (
<CaptureSelectedLanguage>
<Story />
</CaptureSelectedLanguage>
),
],
parameters: {
initialEntries: [`/explorer/${multilingualModels[0].id}/occupations/occ-1120?lang=fr`],
mockData: [
{ url: MODELS_URL, method: "GET", status: 200, response: multilingualModels },
{
url: `${multilingualModelUrl}/occupationGroups?root=true&limit=100`,
method: "GET",
status: 200,
response: () => paginated([multilingualGroup()]),
},
{
url: `${multilingualModelUrl}/occupationGroups/grp-1`,
method: "GET",
status: 200,
response: () => multilingualGroup(),
},
{
url: `${multilingualModelUrl}/occupations/occ-1120`,
method: "GET",
status: 200,
response: () => ({
id: "occ-1120",
UUID: "occ-1120-uuid",
code: "1120",
preferredLabel: texts().occupation,
definition: texts().definition,
altLabels: [],
occupationType: ObjectType.ESCOOccupation,
requiresSkills: [{ id: "skill-1", preferredLabel: texts().skill, relationType: "essential" }],
}),
},
],
},
render: () => (
<Routes>
<Route path={routerPaths.EXPLORER_OCCUPATIONS} element={<ExplorerPage initialTab="occupations" />} />
<Route path={routerPaths.EXPLORER_OCCUPATIONS_DETAIL} element={<ExplorerPage initialTab="occupations" />} />
</Routes>
),
};
Loading