@saooti/octopus-sdk 41.7.2 → 41.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +2 -1
- package/CHANGELOG.md +28 -0
- package/index.ts +6 -2
- package/package.json +1 -1
- package/src/api/emissionApi.ts +44 -1
- package/src/api/podcastApi.ts +27 -5
- package/src/components/composable/route/useAdvancedParamInit.ts +4 -3
- package/src/components/composable/useRights.ts +196 -0
- package/src/components/composable/useSeasonsManagement.ts +43 -0
- package/src/components/display/live/RadioPlanning.vue +6 -4
- package/src/components/display/podcasts/PodcastFilterList.vue +100 -18
- package/src/components/display/podcasts/PodcastInlineListTemplate.vue +4 -1
- package/src/components/display/podcasts/PodcastList.vue +5 -1
- package/src/components/display/podcasts/PodcastModuleBox.vue +21 -4
- package/src/components/display/podcasts/PodcastSwiperList.vue +9 -3
- package/src/components/form/ClassicRadio.vue +13 -14
- package/src/components/misc/TopBar.vue +7 -1
- package/src/components/pages/EmissionPage.vue +22 -10
- package/src/locale/de.json +7 -1
- package/src/locale/en.json +7 -1
- package/src/locale/es.json +7 -1
- package/src/locale/fr.json +7 -1
- package/src/locale/it.json +7 -1
- package/src/locale/sl.json +7 -1
- package/src/stores/class/general/emission.ts +20 -0
- package/src/stores/class/general/podcast.ts +17 -0
- package/src/style/general.scss +7 -0
- package/tests/api/podcastApi.spec.ts +43 -0
- package/tests/components/composable/useAdvancedParamInit.spec.ts +90 -0
- package/tests/components/composable/useRights.spec.ts +265 -0
- package/tests/components/composable/useSeasonsManagement.spec.ts +35 -0
- package/tests/components/display/podcasts/PodcastFilterList.spec.ts +33 -0
- package/tests/components/display/podcasts/PodcastInlineListTemplate.spec.ts +23 -0
- package/tests/components/display/podcasts/PodcastModuleBox.spec.ts +49 -22
- package/tests/components/pages/EmissionPage.spec.ts +86 -0
- package/tests/utils.ts +12 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import '@tests/mocks/i18n';
|
|
2
|
+
import '@tests/mocks/useRouter';
|
|
3
|
+
|
|
4
|
+
import EmissionPage from '@/components/pages/EmissionPage.vue';
|
|
5
|
+
import { emptyEmissionData, SeasonMode } from '@/stores/class/general/emission';
|
|
6
|
+
import { emptyPodcastData, PodcastProcessingStatus } from '@/stores/class/general/podcast';
|
|
7
|
+
import { mount, VueWrapper } from '@tests/utils';
|
|
8
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
9
|
+
import { nextTick } from 'vue';
|
|
10
|
+
|
|
11
|
+
vi.mock('@/api/emissionApi', () => ({
|
|
12
|
+
emissionApi: { get: vi.fn() }
|
|
13
|
+
}));
|
|
14
|
+
vi.mock('@/components/composable/route/useSeoTitleUrl.ts', () => ({
|
|
15
|
+
useSeoTitleUrl: () => ({ updatePathParams: vi.fn() })
|
|
16
|
+
}));
|
|
17
|
+
vi.mock('@/components/composable/useImageProxy', () => ({
|
|
18
|
+
useImageProxy: () => ({ useProxyImageUrl: vi.fn() })
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
import { emissionApi } from '@/api/emissionApi';
|
|
22
|
+
|
|
23
|
+
const publicOrga = { id: 'org-1', name: 'Test', imageUrl: '', privacy: 'PUBLIC' };
|
|
24
|
+
|
|
25
|
+
function makeEmission(seasonMode: SeasonMode) {
|
|
26
|
+
return { ...emptyEmissionData(), seasonMode, seasonCount: 2, orga: publicOrga };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function makeReadyPodcast(seasonMode: SeasonMode = SeasonMode.NO_SEASON) {
|
|
30
|
+
const podcast = emptyPodcastData();
|
|
31
|
+
podcast.processingStatus = PodcastProcessingStatus.Ready;
|
|
32
|
+
podcast.seasonNumber = 1;
|
|
33
|
+
podcast.seasonEpisodeNumber = 3;
|
|
34
|
+
podcast.emission.seasonMode = seasonMode;
|
|
35
|
+
return podcast;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function mountPage(seasonMode: SeasonMode) {
|
|
39
|
+
vi.mocked(emissionApi.get).mockResolvedValue(makeEmission(seasonMode));
|
|
40
|
+
return mount(EmissionPage, { shallow: true, props: { emissionId: 1 } });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function triggerFetch(wrapper: VueWrapper, seasonMode: SeasonMode, season?: number) {
|
|
44
|
+
await wrapper.findComponent({ name: 'PodcastFilterList' }).vm.$emit('fetch', [makeReadyPodcast(seasonMode)], season);
|
|
45
|
+
await nextTick();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
describe('EmissionPage', () => {
|
|
49
|
+
describe('messageListenEpisode', () => {
|
|
50
|
+
it('does not show season info before any podcast is fetched', async () => {
|
|
51
|
+
const wrapper = await mountPage(SeasonMode.SEASON_WITH_PODCAST_NUMBERING);
|
|
52
|
+
expect(wrapper.text()).not.toContain('S1·E3');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('shows base message without season info for NO_SEASON emission', async () => {
|
|
56
|
+
const wrapper = await mountPage(SeasonMode.NO_SEASON);
|
|
57
|
+
await triggerFetch(wrapper, SeasonMode.NO_SEASON);
|
|
58
|
+
expect(wrapper.text()).toContain('Listen to the latest episode');
|
|
59
|
+
expect(wrapper.text()).not.toContain('(S');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it.each([
|
|
63
|
+
{ seasonMode: SeasonMode.SEASON_WITH_PODCAST_NUMBERING, expected: 'Listen to the latest episode (S1·E3)' },
|
|
64
|
+
{ seasonMode: SeasonMode.SEASON_WITHOUT_PODCAST_NUMBERING, expected: 'Listen to the latest episode (S1)' },
|
|
65
|
+
])('appends season info for $seasonMode', async ({ seasonMode, expected }) => {
|
|
66
|
+
const wrapper = await mountPage(seasonMode);
|
|
67
|
+
await triggerFetch(wrapper, seasonMode);
|
|
68
|
+
expect(wrapper.text()).toContain(expected);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('podcastsFetched season filtering', () => {
|
|
73
|
+
// seasonCount is 2 in makeEmission
|
|
74
|
+
it.each([undefined, 2])('shows lastPodcast when season is %s', async (season) => {
|
|
75
|
+
const wrapper = await mountPage(SeasonMode.SEASON_WITH_PODCAST_NUMBERING);
|
|
76
|
+
await triggerFetch(wrapper, SeasonMode.SEASON_WITH_PODCAST_NUMBERING, season);
|
|
77
|
+
expect(wrapper.text()).toContain('Listen to the latest episode');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('ignores podcasts from earlier seasons', async () => {
|
|
81
|
+
const wrapper = await mountPage(SeasonMode.SEASON_WITH_PODCAST_NUMBERING);
|
|
82
|
+
await triggerFetch(wrapper, SeasonMode.SEASON_WITH_PODCAST_NUMBERING, 1);
|
|
83
|
+
expect(wrapper.text()).not.toContain('Listen to the latest episode');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
package/tests/utils.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Component } from 'vue';
|
|
2
2
|
import { vi } from 'vitest';
|
|
3
3
|
import { mount as _mount, VueWrapper } from '@vue/test-utils';
|
|
4
|
-
import { type Pinia, setActivePinia } from 'pinia';
|
|
4
|
+
import { type Pinia, setActivePinia, createPinia } from 'pinia';
|
|
5
5
|
import { createTestingPinia } from '@pinia/testing';
|
|
6
6
|
|
|
7
7
|
import { useAuthStore } from '../src/stores/AuthStore';
|
|
@@ -159,3 +159,14 @@ export function combineStoreSetups(...setups: Array<() => void>) {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
export { VueWrapper };
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Creates a Pinia instance without mounting a component.
|
|
165
|
+
* Use this for testing composables or APIs directly.
|
|
166
|
+
*/
|
|
167
|
+
export function setupPinia(setupFn?: () => void | Promise<void>): Pinia {
|
|
168
|
+
const pinia = createPinia();
|
|
169
|
+
setActivePinia(pinia);
|
|
170
|
+
if (setupFn) { setupFn(); }
|
|
171
|
+
return pinia;
|
|
172
|
+
}
|