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
39 changes: 39 additions & 0 deletions src/stores/bootstrapStore.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { createTestingPinia } from '@pinia/testing'
import type { AxiosResponse } from 'axios'
import { AxiosError } from 'axios'
import { setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { nextTick, ref } from 'vue'

import { mergeCustomNodesI18n } from '@/i18n'
import { useSettingStore } from '@/platform/settings/settingStore'
import { api } from '@/scripts/api'

import { useBootstrapStore } from './bootstrapStore'

Expand Down Expand Up @@ -64,6 +68,12 @@ const mockDistributionTypes = vi.hoisted(() => ({
}))
vi.mock('@/platform/distribution/types', () => mockDistributionTypes)

function requestFailure(status: number) {
const error = new AxiosError(`Request failed with status code ${status}`)
error.response = { status } as AxiosResponse
return error
}

describe('bootstrapStore', () => {
beforeEach(() => {
mockIsSettingsReady.value = false
Expand Down Expand Up @@ -93,6 +103,35 @@ describe('bootstrapStore', () => {
})
})

describe('custom node translations', () => {
it('treats a missing /api/i18n endpoint as no translations', async () => {
vi.mocked(api.getCustomNodesI18n).mockRejectedValueOnce(
requestFailure(404)
)
const store = useBootstrapStore()
void store.startStoreBootstrap()

await vi.waitFor(() => {
expect(store.isI18nReady).toBe(true)
})
expect(store.i18nError).toBeUndefined()
expect(mergeCustomNodesI18n).not.toHaveBeenCalled()
})

it('surfaces failures other than a missing endpoint', async () => {
vi.mocked(api.getCustomNodesI18n).mockRejectedValueOnce(
requestFailure(500)
)
const store = useBootstrapStore()
void store.startStoreBootstrap()

await vi.waitFor(() => {
expect(store.i18nError).toBeDefined()
})
expect(store.isI18nReady).toBe(false)
})
})

describe('cloud mode', () => {
beforeEach(() => {
mockDistributionTypes.isCloud = true
Expand Down
19 changes: 17 additions & 2 deletions src/stores/bootstrapStore.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
import { until, useAsyncState } from '@vueuse/core'
import axios from 'axios'
import { defineStore, storeToRefs } from 'pinia'

import { isCloud } from '@/platform/distribution/types'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
import type { CustomNodesI18n } from '@/schemas/apiSchema'
import { api } from '@/scripts/api'
import { useAuthStore } from '@/stores/authStore'
import { useUserStore } from '@/stores/userStore'

/**
* Backends that vendor no custom-node locale files do not implement
* `/api/i18n`, so a 404 means "no custom-node translations", not a failure.
*/
async function fetchCustomNodesI18n(): Promise<CustomNodesI18n | undefined> {
try {
return await api.getCustomNodesI18n()
} catch (error) {
if (axios.isAxiosError(error) && error.response?.status === 404) return
throw error
}
}

export const useBootstrapStore = defineStore('bootstrap', () => {
const settingStore = useSettingStore()
const workflowStore = useWorkflowStore()
Expand All @@ -19,8 +34,8 @@ export const useBootstrapStore = defineStore('bootstrap', () => {
} = useAsyncState(
async () => {
const { mergeCustomNodesI18n } = await import('@/i18n')
const i18nData = await api.getCustomNodesI18n()
mergeCustomNodesI18n(i18nData)
const i18nData = await fetchCustomNodesI18n()
if (i18nData) mergeCustomNodesI18n(i18nData)
},
undefined,
{ immediate: false }
Expand Down
Loading