@getmicdrop/svelte-components 2.0.4 → 2.0.6
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/dist/components/Alert/Alert.spec.js +170 -170
- package/dist/components/Badges/Badge.spec.js +103 -103
- package/dist/components/BottomSheet/BottomSheet.spec.js +127 -127
- package/dist/components/Breadcrumb/Breadcrumb.spec.js +120 -120
- package/dist/components/Button/Button.spec.js +211 -211
- package/dist/components/Button/ButtonSaveDemo.spec.js +48 -48
- package/dist/components/Calendar/Calendar.spec.js +131 -131
- package/dist/components/Calendar/QuarterView.spec.js +394 -394
- package/dist/components/Card.spec.js +47 -47
- package/dist/components/CropImage/CropImage.spec.js +216 -216
- package/dist/components/DarkModeToggle.spec.js +357 -357
- package/dist/components/ErrorDisplay.spec.js +69 -69
- package/dist/components/FormActions.spec.js +88 -88
- package/dist/components/FormValidationSummary.spec.js +203 -203
- package/dist/components/Icons/Icon.spec.js +175 -175
- package/dist/components/Icons/MoreHori.spec.js +67 -67
- package/dist/components/Icons/WarningIcon.spec.js +30 -30
- package/dist/components/Input/Input.spec.js +573 -573
- package/dist/components/Input/MultiSelect.spec.js +257 -257
- package/dist/components/Input/OTPInput.spec.js +238 -238
- package/dist/components/Input/Select.spec.js +218 -218
- package/dist/components/Layout/BottomNav.spec.js +130 -130
- package/dist/components/Layout/Header.spec.js +203 -203
- package/dist/components/Modal/ConfirmationModal.spec.js +191 -191
- package/dist/components/Modal/Modal.spec.js +95 -95
- package/dist/components/Modal/ModalStateManager.spec.js +100 -100
- package/dist/components/PageLoader.spec.js +54 -54
- package/dist/components/PasswordStrengthIndicator/PasswordStrengthIndicator.spec.js +173 -173
- package/dist/components/PlaceAutocomplete/PlaceAutocomplete.spec.js +300 -300
- package/dist/components/Spinner/Spinner.spec.js +75 -75
- package/dist/components/StatusIndicator/StatusIndicator.spec.js +129 -129
- package/dist/components/Toaster/Toaster.stories.svelte +1 -1
- package/dist/components/Toggle.spec.js +158 -158
- package/dist/components/ValidationError.spec.js +79 -79
- package/dist/components/pages/performers/AvailabilityCalendarModal.spec.js +606 -606
- package/dist/components/pages/performers/AvailabilityCalendarModal.svelte +4 -4
- package/dist/components/pages/performers/ModalShowInfo.spec.js +124 -124
- package/dist/components/pages/performers/ModalShowInfo.svelte +1 -1
- package/dist/components/pages/performers/PageBackButton.spec.js +89 -89
- package/dist/components/pages/performers/SectionHeader.spec.js +75 -75
- package/dist/components/pages/performers/ShowDetails.spec.js +166 -166
- package/dist/components/pages/performers/ShowItemCard.spec.js +793 -793
- package/dist/components/pages/performers/ShowItemCard.svelte +4 -4
- package/dist/components/pages/performers/SwitchOption.spec.js +127 -127
- package/dist/components/pages/performers/VenueInfo.spec.js +167 -167
- package/dist/components/pages/performers/VenueInfo.svelte +1 -1
- package/dist/components/pages/performers/VenueItemCard.spec.js +763 -763
- package/dist/components/pages/performers/VenueItemCard.svelte +4 -4
- package/dist/components/pages/profile/profile-form.spec.js +9 -9
- package/dist/components/pages/settings/tabs/CustomImageDropzone.svelte +3 -3
- package/dist/components/pages/shows/ShowList.spec.js +33 -33
- package/dist/components/pages/shows/TabContent.spec.js +90 -90
- package/dist/components/pages/shows/TabNavigation.spec.js +143 -143
- package/dist/config.js +5 -5
- package/dist/config.spec.js +29 -29
- package/dist/constants/formOptions.js +25 -25
- package/dist/constants/formOptions.spec.js +88 -88
- package/dist/index.js +111 -111
- package/dist/stores/auth.d.ts +9 -0
- package/dist/stores/auth.d.ts.map +1 -0
- package/dist/stores/auth.js +36 -0
- package/dist/stores/auth.spec.d.ts +2 -0
- package/dist/stores/auth.spec.d.ts.map +1 -0
- package/dist/stores/auth.spec.js +139 -0
- package/dist/stores/formDataStore.d.ts +17 -0
- package/dist/stores/formDataStore.d.ts.map +1 -0
- package/dist/stores/formDataStore.js +25 -0
- package/dist/stores/formDataStore.spec.d.ts +2 -0
- package/dist/stores/formDataStore.spec.d.ts.map +1 -0
- package/dist/stores/formDataStore.spec.js +257 -0
- package/dist/stores/formSave.d.ts +24 -0
- package/dist/stores/formSave.d.ts.map +1 -0
- package/dist/stores/formSave.js +132 -0
- package/dist/stores/formSave.spec.d.ts +2 -0
- package/dist/stores/formSave.spec.d.ts.map +1 -0
- package/dist/stores/formSave.spec.js +296 -0
- package/dist/stores/index.d.ts +1 -0
- package/dist/stores/index.d.ts.map +1 -0
- package/dist/stores/index.js +0 -0
- package/dist/stores/navigation.d.ts +5 -0
- package/dist/stores/navigation.d.ts.map +1 -0
- package/dist/stores/navigation.js +12 -0
- package/dist/stores/navigation.spec.d.ts +2 -0
- package/dist/stores/navigation.spec.d.ts.map +1 -0
- package/dist/stores/navigation.spec.js +136 -0
- package/dist/stores/toaster.d.ts +4 -0
- package/dist/stores/toaster.d.ts.map +1 -0
- package/dist/stores/toaster.js +13 -0
- package/dist/stores/toaster.spec.d.ts +2 -0
- package/dist/stores/toaster.spec.d.ts.map +1 -0
- package/dist/stores/toaster.spec.js +59 -0
- package/dist/telemetry.js +357 -357
- package/dist/telemetry.server.js +211 -211
- package/dist/telemetry.server.spec.js +434 -434
- package/dist/telemetry.spec.js +660 -660
- package/dist/utils/apiConfig.js +49 -49
- package/dist/utils/apiConfig.spec.js +118 -118
- package/dist/utils/greetings.js +187 -187
- package/dist/utils/greetings.spec.js +337 -337
- package/dist/utils/imageValidation.js +121 -121
- package/dist/utils/imageValidation.spec.js +220 -220
- package/dist/utils/portal.js +25 -25
- package/dist/utils/portal.spec.js +143 -143
- package/dist/utils/utils/utils.js +323 -323
- package/dist/utils/utils/utils.spec.js +698 -698
- package/dist/utils/utils.spec.js +643 -643
- package/package.json +1 -1
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import Input from "../../Input/Input.svelte";
|
|
3
3
|
import Modal from "../../Modal/Modal.svelte";
|
|
4
4
|
import VenueInfo from "./VenueInfo.svelte";
|
|
5
|
-
import { showToast } from "
|
|
6
|
-
import { getPerformerToken } from "
|
|
7
|
-
import { timeAgo } from "
|
|
8
|
-
import { buildApiUrl, API_ENDPOINTS } from "
|
|
5
|
+
import { showToast } from "../../stores/toaster";
|
|
6
|
+
import { getPerformerToken } from "../../utils/utils";
|
|
7
|
+
import { timeAgo } from "../../utils/utils/utils";
|
|
8
|
+
import { buildApiUrl, API_ENDPOINTS } from "../../utils/apiConfig";
|
|
9
9
|
import { Dropdown, DropdownItem } from "flowbite-svelte";
|
|
10
10
|
import { DotsHorizontalOutline } from "flowbite-svelte-icons";
|
|
11
11
|
import Button from "../../Button/Button.svelte";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
// Skip profile-form tests - complex component with many dependencies
|
|
4
|
-
// This component is better tested via E2E tests
|
|
5
|
-
describe.skip('ProfileForm', () => {
|
|
6
|
-
it('placeholder', () => {
|
|
7
|
-
expect(true).toBe(true);
|
|
8
|
-
});
|
|
9
|
-
});
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
// Skip profile-form tests - complex component with many dependencies
|
|
4
|
+
// This component is better tested via E2E tests
|
|
5
|
+
describe.skip('ProfileForm', () => {
|
|
6
|
+
it('placeholder', () => {
|
|
7
|
+
expect(true).toBe(true);
|
|
8
|
+
});
|
|
9
|
+
});
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
export let readonly = false;
|
|
5
5
|
export let shape = "default";
|
|
6
6
|
export let label = "";
|
|
7
|
-
import CancelIcon from "
|
|
7
|
+
import CancelIcon from "../../../assets/svg/cancel.svg";
|
|
8
8
|
|
|
9
|
-
import AddMain from "
|
|
10
|
-
import CloudUpload from "
|
|
9
|
+
import AddMain from "../../../assets/svg/add-main-01.svg";
|
|
10
|
+
import CloudUpload from "../../../assets/svg/cloud-upload.svg";
|
|
11
11
|
|
|
12
12
|
let images = [];
|
|
13
13
|
let error = "";
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { render } from '@testing-library/svelte';
|
|
3
|
-
import ShowList from './ShowList.svelte';
|
|
4
|
-
|
|
5
|
-
describe('ShowList Component', () => {
|
|
6
|
-
it('renders empty list when no shows provided', () => {
|
|
7
|
-
const { container } = render(ShowList, { props: { shows: [], status: '' } });
|
|
8
|
-
const grid = container.querySelector('.grid');
|
|
9
|
-
expect(grid).toBeTruthy();
|
|
10
|
-
expect(grid.children.length).toBe(0);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('has grid layout classes', () => {
|
|
14
|
-
const { container } = render(ShowList, { props: { shows: [], status: '' } });
|
|
15
|
-
const grid = container.querySelector('.grid');
|
|
16
|
-
expect(grid.classList.contains('grid-cols-1')).toBe(true);
|
|
17
|
-
expect(grid.classList.contains('lg:grid-cols-2')).toBe(true);
|
|
18
|
-
expect(grid.classList.contains('gap-4')).toBe(true);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('has responsive margin-top classes', () => {
|
|
22
|
-
const { container } = render(ShowList, { props: { shows: [], status: '' } });
|
|
23
|
-
const grid = container.querySelector('.grid');
|
|
24
|
-
expect(grid.classList.contains('mt-0')).toBe(true);
|
|
25
|
-
expect(grid.classList.contains('sm:mt-2')).toBe(true);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('has items-start alignment', () => {
|
|
29
|
-
const { container } = render(ShowList, { props: { shows: [], status: '' } });
|
|
30
|
-
const grid = container.querySelector('.grid');
|
|
31
|
-
expect(grid.classList.contains('items-start')).toBe(true);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { render } from '@testing-library/svelte';
|
|
3
|
+
import ShowList from './ShowList.svelte';
|
|
4
|
+
|
|
5
|
+
describe('ShowList Component', () => {
|
|
6
|
+
it('renders empty list when no shows provided', () => {
|
|
7
|
+
const { container } = render(ShowList, { props: { shows: [], status: '' } });
|
|
8
|
+
const grid = container.querySelector('.grid');
|
|
9
|
+
expect(grid).toBeTruthy();
|
|
10
|
+
expect(grid.children.length).toBe(0);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('has grid layout classes', () => {
|
|
14
|
+
const { container } = render(ShowList, { props: { shows: [], status: '' } });
|
|
15
|
+
const grid = container.querySelector('.grid');
|
|
16
|
+
expect(grid.classList.contains('grid-cols-1')).toBe(true);
|
|
17
|
+
expect(grid.classList.contains('lg:grid-cols-2')).toBe(true);
|
|
18
|
+
expect(grid.classList.contains('gap-4')).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('has responsive margin-top classes', () => {
|
|
22
|
+
const { container } = render(ShowList, { props: { shows: [], status: '' } });
|
|
23
|
+
const grid = container.querySelector('.grid');
|
|
24
|
+
expect(grid.classList.contains('mt-0')).toBe(true);
|
|
25
|
+
expect(grid.classList.contains('sm:mt-2')).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('has items-start alignment', () => {
|
|
29
|
+
const { container } = render(ShowList, { props: { shows: [], status: '' } });
|
|
30
|
+
const grid = container.querySelector('.grid');
|
|
31
|
+
expect(grid.classList.contains('items-start')).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -1,90 +1,90 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
// TabContent has complex child component dependencies (SectionHeader, ShowList)
|
|
4
|
-
// that don't mock properly with testing-library/svelte.
|
|
5
|
-
// The component logic is tested through its child components and E2E tests.
|
|
6
|
-
|
|
7
|
-
describe('TabContent Component Logic', () => {
|
|
8
|
-
describe('content configuration', () => {
|
|
9
|
-
// Testing the content object structure
|
|
10
|
-
const content = {
|
|
11
|
-
upcoming: {
|
|
12
|
-
title: "Upcoming shows",
|
|
13
|
-
description:
|
|
14
|
-
"Currently, there are no upcoming shows. Once a venue schedules a new show, it will appear here.",
|
|
15
|
-
},
|
|
16
|
-
invitations: {
|
|
17
|
-
title: "Booking invites",
|
|
18
|
-
description:
|
|
19
|
-
"You currently have no show invites. Once you receive an invite, it will appear here.",
|
|
20
|
-
},
|
|
21
|
-
declined: {
|
|
22
|
-
title: "Declined invites",
|
|
23
|
-
description:
|
|
24
|
-
"You haven't declined any shows yet. Once you decline an invitation, it will appear here.",
|
|
25
|
-
notice: "Events on this page will be automatically removed after 30 days.",
|
|
26
|
-
},
|
|
27
|
-
past: {
|
|
28
|
-
title: "Past shows",
|
|
29
|
-
description:
|
|
30
|
-
"You currently have no past shows. Once you complete a show, it will be listed here.",
|
|
31
|
-
notice: "Events on this page will be automatically removed after 30 days.",
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
it('has upcoming content with title and description', () => {
|
|
36
|
-
expect(content.upcoming.title).toBe('Upcoming shows');
|
|
37
|
-
expect(content.upcoming.description).toBeDefined();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('has invitations content with title and description', () => {
|
|
41
|
-
expect(content.invitations.title).toBe('Booking invites');
|
|
42
|
-
expect(content.invitations.description).toBeDefined();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('has declined content with title, description, and notice', () => {
|
|
46
|
-
expect(content.declined.title).toBe('Declined invites');
|
|
47
|
-
expect(content.declined.description).toBeDefined();
|
|
48
|
-
expect(content.declined.notice).toContain('30 days');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('has past content with title, description, and notice', () => {
|
|
52
|
-
expect(content.past.title).toBe('Past shows');
|
|
53
|
-
expect(content.past.description).toBeDefined();
|
|
54
|
-
expect(content.past.notice).toContain('30 days');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('upcoming and invitations do not have notice', () => {
|
|
58
|
-
expect(content.upcoming.notice).toBeUndefined();
|
|
59
|
-
expect(content.invitations.notice).toBeUndefined();
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
describe('loadedItems structure', () => {
|
|
64
|
-
const createLoadedItems = () => ({
|
|
65
|
-
upcoming: { data: [], isMoreLoading: false },
|
|
66
|
-
invitations: { data: [], isMoreLoading: false },
|
|
67
|
-
declined: { data: [], isMoreLoading: false },
|
|
68
|
-
past: { data: [], isMoreLoading: false },
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('creates correct structure with data array', () => {
|
|
72
|
-
const items = createLoadedItems();
|
|
73
|
-
expect(Array.isArray(items.upcoming.data)).toBe(true);
|
|
74
|
-
expect(Array.isArray(items.invitations.data)).toBe(true);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('creates correct structure with isMoreLoading flag', () => {
|
|
78
|
-
const items = createLoadedItems();
|
|
79
|
-
expect(typeof items.upcoming.isMoreLoading).toBe('boolean');
|
|
80
|
-
expect(typeof items.past.isMoreLoading).toBe('boolean');
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
describe('IntersectionObserver threshold', () => {
|
|
85
|
-
it('uses 0.1 threshold for infinite scroll', () => {
|
|
86
|
-
const threshold = 0.1;
|
|
87
|
-
expect(threshold).toBe(0.1);
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
});
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
// TabContent has complex child component dependencies (SectionHeader, ShowList)
|
|
4
|
+
// that don't mock properly with testing-library/svelte.
|
|
5
|
+
// The component logic is tested through its child components and E2E tests.
|
|
6
|
+
|
|
7
|
+
describe('TabContent Component Logic', () => {
|
|
8
|
+
describe('content configuration', () => {
|
|
9
|
+
// Testing the content object structure
|
|
10
|
+
const content = {
|
|
11
|
+
upcoming: {
|
|
12
|
+
title: "Upcoming shows",
|
|
13
|
+
description:
|
|
14
|
+
"Currently, there are no upcoming shows. Once a venue schedules a new show, it will appear here.",
|
|
15
|
+
},
|
|
16
|
+
invitations: {
|
|
17
|
+
title: "Booking invites",
|
|
18
|
+
description:
|
|
19
|
+
"You currently have no show invites. Once you receive an invite, it will appear here.",
|
|
20
|
+
},
|
|
21
|
+
declined: {
|
|
22
|
+
title: "Declined invites",
|
|
23
|
+
description:
|
|
24
|
+
"You haven't declined any shows yet. Once you decline an invitation, it will appear here.",
|
|
25
|
+
notice: "Events on this page will be automatically removed after 30 days.",
|
|
26
|
+
},
|
|
27
|
+
past: {
|
|
28
|
+
title: "Past shows",
|
|
29
|
+
description:
|
|
30
|
+
"You currently have no past shows. Once you complete a show, it will be listed here.",
|
|
31
|
+
notice: "Events on this page will be automatically removed after 30 days.",
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
it('has upcoming content with title and description', () => {
|
|
36
|
+
expect(content.upcoming.title).toBe('Upcoming shows');
|
|
37
|
+
expect(content.upcoming.description).toBeDefined();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('has invitations content with title and description', () => {
|
|
41
|
+
expect(content.invitations.title).toBe('Booking invites');
|
|
42
|
+
expect(content.invitations.description).toBeDefined();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('has declined content with title, description, and notice', () => {
|
|
46
|
+
expect(content.declined.title).toBe('Declined invites');
|
|
47
|
+
expect(content.declined.description).toBeDefined();
|
|
48
|
+
expect(content.declined.notice).toContain('30 days');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('has past content with title, description, and notice', () => {
|
|
52
|
+
expect(content.past.title).toBe('Past shows');
|
|
53
|
+
expect(content.past.description).toBeDefined();
|
|
54
|
+
expect(content.past.notice).toContain('30 days');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('upcoming and invitations do not have notice', () => {
|
|
58
|
+
expect(content.upcoming.notice).toBeUndefined();
|
|
59
|
+
expect(content.invitations.notice).toBeUndefined();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('loadedItems structure', () => {
|
|
64
|
+
const createLoadedItems = () => ({
|
|
65
|
+
upcoming: { data: [], isMoreLoading: false },
|
|
66
|
+
invitations: { data: [], isMoreLoading: false },
|
|
67
|
+
declined: { data: [], isMoreLoading: false },
|
|
68
|
+
past: { data: [], isMoreLoading: false },
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('creates correct structure with data array', () => {
|
|
72
|
+
const items = createLoadedItems();
|
|
73
|
+
expect(Array.isArray(items.upcoming.data)).toBe(true);
|
|
74
|
+
expect(Array.isArray(items.invitations.data)).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('creates correct structure with isMoreLoading flag', () => {
|
|
78
|
+
const items = createLoadedItems();
|
|
79
|
+
expect(typeof items.upcoming.isMoreLoading).toBe('boolean');
|
|
80
|
+
expect(typeof items.past.isMoreLoading).toBe('boolean');
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('IntersectionObserver threshold', () => {
|
|
85
|
+
it('uses 0.1 threshold for infinite scroll', () => {
|
|
86
|
+
const threshold = 0.1;
|
|
87
|
+
expect(threshold).toBe(0.1);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -1,143 +1,143 @@
|
|
|
1
|
-
import { render, screen, fireEvent } from "@testing-library/svelte";
|
|
2
|
-
import userEvent from "@testing-library/user-event";
|
|
3
|
-
import { expect, describe, test, vi } from "vitest";
|
|
4
|
-
import TabNavigation from "./TabNavigation.svelte";
|
|
5
|
-
|
|
6
|
-
const sampleTabs = [
|
|
7
|
-
{ key: "upcoming", label: "Upcoming" },
|
|
8
|
-
{ key: "invitations", label: "Invitations", badge: () => 3 },
|
|
9
|
-
{ key: "declined", label: "Declined" },
|
|
10
|
-
{ key: "past", label: "Past" },
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
function setupTest(args = {}) {
|
|
14
|
-
const user = userEvent.setup();
|
|
15
|
-
const { component, container } = render(TabNavigation, {
|
|
16
|
-
props: {
|
|
17
|
-
tabs: sampleTabs,
|
|
18
|
-
activeTab: "upcoming",
|
|
19
|
-
...args,
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
return { user, component, container };
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
describe("TabNavigation Component Tests", () => {
|
|
26
|
-
test("Renders all tabs", () => {
|
|
27
|
-
setupTest();
|
|
28
|
-
expect(screen.getByText("Upcoming")).toBeInTheDocument();
|
|
29
|
-
expect(screen.getByText("Invitations")).toBeInTheDocument();
|
|
30
|
-
expect(screen.getByText("Declined")).toBeInTheDocument();
|
|
31
|
-
expect(screen.getByText("Past")).toBeInTheDocument();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test("Tabs have tab role", () => {
|
|
35
|
-
setupTest();
|
|
36
|
-
const tabs = screen.getAllByRole("tab");
|
|
37
|
-
expect(tabs.length).toBe(4);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test("Active tab has active class", () => {
|
|
41
|
-
setupTest({ activeTab: "upcoming" });
|
|
42
|
-
const upcomingTab = screen.getByText("Upcoming").closest('[role="tab"]');
|
|
43
|
-
expect(upcomingTab).toHaveClass("active");
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test("Non-active tabs do not have active class", () => {
|
|
47
|
-
setupTest({ activeTab: "upcoming" });
|
|
48
|
-
const declinedTab = screen.getByText("Declined").closest('[role="tab"]');
|
|
49
|
-
expect(declinedTab).not.toHaveClass("active");
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test("Dispatches tabChange event on click", async () => {
|
|
53
|
-
const { user, component } = setupTest({ activeTab: "upcoming" });
|
|
54
|
-
const changeSpy = vi.fn();
|
|
55
|
-
component.$on("tabChange", changeSpy);
|
|
56
|
-
|
|
57
|
-
await user.click(screen.getByText("Declined"));
|
|
58
|
-
|
|
59
|
-
expect(changeSpy).toHaveBeenCalled();
|
|
60
|
-
expect(changeSpy.mock.calls[0][0].detail).toBe("declined");
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test("Dispatches tabChange event on Enter key", async () => {
|
|
64
|
-
const { user, component } = setupTest({ activeTab: "upcoming" });
|
|
65
|
-
const changeSpy = vi.fn();
|
|
66
|
-
component.$on("tabChange", changeSpy);
|
|
67
|
-
|
|
68
|
-
const declinedTab = screen.getByText("Declined").closest('[role="tab"]');
|
|
69
|
-
declinedTab.focus();
|
|
70
|
-
await user.keyboard("{Enter}");
|
|
71
|
-
|
|
72
|
-
expect(changeSpy).toHaveBeenCalled();
|
|
73
|
-
expect(changeSpy.mock.calls[0][0].detail).toBe("declined");
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test("Tabs are focusable", () => {
|
|
77
|
-
setupTest();
|
|
78
|
-
const tabs = screen.getAllByRole("tab");
|
|
79
|
-
tabs.forEach((tab) => {
|
|
80
|
-
expect(tab).toHaveAttribute("tabindex", "0");
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test("Shows badge indicator for invitations when badge returns truthy", () => {
|
|
85
|
-
const { container } = setupTest({ activeTab: "upcoming" });
|
|
86
|
-
// Look for the red dot badge
|
|
87
|
-
const badge = container.querySelector(".bg-red-500.rounded-full");
|
|
88
|
-
expect(badge).toBeInTheDocument();
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test("Does not show badge for tabs without badge function", () => {
|
|
92
|
-
const tabsWithoutBadge = [
|
|
93
|
-
{ key: "upcoming", label: "Upcoming" },
|
|
94
|
-
{ key: "past", label: "Past" },
|
|
95
|
-
];
|
|
96
|
-
const { container } = render(TabNavigation, {
|
|
97
|
-
props: { tabs: tabsWithoutBadge, activeTab: "upcoming" },
|
|
98
|
-
});
|
|
99
|
-
const badges = container.querySelectorAll(".bg-red-500.rounded-full");
|
|
100
|
-
expect(badges.length).toBe(0);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
test("Has flex layout", () => {
|
|
104
|
-
const { container } = setupTest();
|
|
105
|
-
const wrapper = container.firstChild;
|
|
106
|
-
expect(wrapper).toHaveClass("flex");
|
|
107
|
-
expect(wrapper).toHaveClass("flex-row");
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test("Switching active tab updates appearance", async () => {
|
|
111
|
-
const { user, component } = setupTest({ activeTab: "upcoming" });
|
|
112
|
-
|
|
113
|
-
// Initially upcoming is active
|
|
114
|
-
let upcomingTab = screen.getByText("Upcoming").closest('[role="tab"]');
|
|
115
|
-
expect(upcomingTab).toHaveClass("active");
|
|
116
|
-
|
|
117
|
-
// Update the active tab prop
|
|
118
|
-
await component.$set({ activeTab: "past" });
|
|
119
|
-
|
|
120
|
-
// Now past should be active
|
|
121
|
-
const pastTab = screen.getByText("Past").closest('[role="tab"]');
|
|
122
|
-
expect(pastTab).toHaveClass("active");
|
|
123
|
-
|
|
124
|
-
// And upcoming should no longer be active
|
|
125
|
-
upcomingTab = screen.getByText("Upcoming").closest('[role="tab"]');
|
|
126
|
-
expect(upcomingTab).not.toHaveClass("active");
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
test("Works with empty tabs array", () => {
|
|
130
|
-
const { container } = render(TabNavigation, {
|
|
131
|
-
props: { tabs: [], activeTab: "" },
|
|
132
|
-
});
|
|
133
|
-
const tabs = screen.queryAllByRole("tab");
|
|
134
|
-
expect(tabs.length).toBe(0);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
test("Works with single tab", () => {
|
|
138
|
-
render(TabNavigation, {
|
|
139
|
-
props: { tabs: [{ key: "only", label: "Only Tab" }], activeTab: "only" },
|
|
140
|
-
});
|
|
141
|
-
expect(screen.getByText("Only Tab")).toBeInTheDocument();
|
|
142
|
-
});
|
|
143
|
-
});
|
|
1
|
+
import { render, screen, fireEvent } from "@testing-library/svelte";
|
|
2
|
+
import userEvent from "@testing-library/user-event";
|
|
3
|
+
import { expect, describe, test, vi } from "vitest";
|
|
4
|
+
import TabNavigation from "./TabNavigation.svelte";
|
|
5
|
+
|
|
6
|
+
const sampleTabs = [
|
|
7
|
+
{ key: "upcoming", label: "Upcoming" },
|
|
8
|
+
{ key: "invitations", label: "Invitations", badge: () => 3 },
|
|
9
|
+
{ key: "declined", label: "Declined" },
|
|
10
|
+
{ key: "past", label: "Past" },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
function setupTest(args = {}) {
|
|
14
|
+
const user = userEvent.setup();
|
|
15
|
+
const { component, container } = render(TabNavigation, {
|
|
16
|
+
props: {
|
|
17
|
+
tabs: sampleTabs,
|
|
18
|
+
activeTab: "upcoming",
|
|
19
|
+
...args,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
return { user, component, container };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe("TabNavigation Component Tests", () => {
|
|
26
|
+
test("Renders all tabs", () => {
|
|
27
|
+
setupTest();
|
|
28
|
+
expect(screen.getByText("Upcoming")).toBeInTheDocument();
|
|
29
|
+
expect(screen.getByText("Invitations")).toBeInTheDocument();
|
|
30
|
+
expect(screen.getByText("Declined")).toBeInTheDocument();
|
|
31
|
+
expect(screen.getByText("Past")).toBeInTheDocument();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("Tabs have tab role", () => {
|
|
35
|
+
setupTest();
|
|
36
|
+
const tabs = screen.getAllByRole("tab");
|
|
37
|
+
expect(tabs.length).toBe(4);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("Active tab has active class", () => {
|
|
41
|
+
setupTest({ activeTab: "upcoming" });
|
|
42
|
+
const upcomingTab = screen.getByText("Upcoming").closest('[role="tab"]');
|
|
43
|
+
expect(upcomingTab).toHaveClass("active");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("Non-active tabs do not have active class", () => {
|
|
47
|
+
setupTest({ activeTab: "upcoming" });
|
|
48
|
+
const declinedTab = screen.getByText("Declined").closest('[role="tab"]');
|
|
49
|
+
expect(declinedTab).not.toHaveClass("active");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("Dispatches tabChange event on click", async () => {
|
|
53
|
+
const { user, component } = setupTest({ activeTab: "upcoming" });
|
|
54
|
+
const changeSpy = vi.fn();
|
|
55
|
+
component.$on("tabChange", changeSpy);
|
|
56
|
+
|
|
57
|
+
await user.click(screen.getByText("Declined"));
|
|
58
|
+
|
|
59
|
+
expect(changeSpy).toHaveBeenCalled();
|
|
60
|
+
expect(changeSpy.mock.calls[0][0].detail).toBe("declined");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("Dispatches tabChange event on Enter key", async () => {
|
|
64
|
+
const { user, component } = setupTest({ activeTab: "upcoming" });
|
|
65
|
+
const changeSpy = vi.fn();
|
|
66
|
+
component.$on("tabChange", changeSpy);
|
|
67
|
+
|
|
68
|
+
const declinedTab = screen.getByText("Declined").closest('[role="tab"]');
|
|
69
|
+
declinedTab.focus();
|
|
70
|
+
await user.keyboard("{Enter}");
|
|
71
|
+
|
|
72
|
+
expect(changeSpy).toHaveBeenCalled();
|
|
73
|
+
expect(changeSpy.mock.calls[0][0].detail).toBe("declined");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("Tabs are focusable", () => {
|
|
77
|
+
setupTest();
|
|
78
|
+
const tabs = screen.getAllByRole("tab");
|
|
79
|
+
tabs.forEach((tab) => {
|
|
80
|
+
expect(tab).toHaveAttribute("tabindex", "0");
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("Shows badge indicator for invitations when badge returns truthy", () => {
|
|
85
|
+
const { container } = setupTest({ activeTab: "upcoming" });
|
|
86
|
+
// Look for the red dot badge
|
|
87
|
+
const badge = container.querySelector(".bg-red-500.rounded-full");
|
|
88
|
+
expect(badge).toBeInTheDocument();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("Does not show badge for tabs without badge function", () => {
|
|
92
|
+
const tabsWithoutBadge = [
|
|
93
|
+
{ key: "upcoming", label: "Upcoming" },
|
|
94
|
+
{ key: "past", label: "Past" },
|
|
95
|
+
];
|
|
96
|
+
const { container } = render(TabNavigation, {
|
|
97
|
+
props: { tabs: tabsWithoutBadge, activeTab: "upcoming" },
|
|
98
|
+
});
|
|
99
|
+
const badges = container.querySelectorAll(".bg-red-500.rounded-full");
|
|
100
|
+
expect(badges.length).toBe(0);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("Has flex layout", () => {
|
|
104
|
+
const { container } = setupTest();
|
|
105
|
+
const wrapper = container.firstChild;
|
|
106
|
+
expect(wrapper).toHaveClass("flex");
|
|
107
|
+
expect(wrapper).toHaveClass("flex-row");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("Switching active tab updates appearance", async () => {
|
|
111
|
+
const { user, component } = setupTest({ activeTab: "upcoming" });
|
|
112
|
+
|
|
113
|
+
// Initially upcoming is active
|
|
114
|
+
let upcomingTab = screen.getByText("Upcoming").closest('[role="tab"]');
|
|
115
|
+
expect(upcomingTab).toHaveClass("active");
|
|
116
|
+
|
|
117
|
+
// Update the active tab prop
|
|
118
|
+
await component.$set({ activeTab: "past" });
|
|
119
|
+
|
|
120
|
+
// Now past should be active
|
|
121
|
+
const pastTab = screen.getByText("Past").closest('[role="tab"]');
|
|
122
|
+
expect(pastTab).toHaveClass("active");
|
|
123
|
+
|
|
124
|
+
// And upcoming should no longer be active
|
|
125
|
+
upcomingTab = screen.getByText("Upcoming").closest('[role="tab"]');
|
|
126
|
+
expect(upcomingTab).not.toHaveClass("active");
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test("Works with empty tabs array", () => {
|
|
130
|
+
const { container } = render(TabNavigation, {
|
|
131
|
+
props: { tabs: [], activeTab: "" },
|
|
132
|
+
});
|
|
133
|
+
const tabs = screen.queryAllByRole("tab");
|
|
134
|
+
expect(tabs.length).toBe(0);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("Works with single tab", () => {
|
|
138
|
+
render(TabNavigation, {
|
|
139
|
+
props: { tabs: [{ key: "only", label: "Only Tab" }], activeTab: "only" },
|
|
140
|
+
});
|
|
141
|
+
expect(screen.getByText("Only Tab")).toBeInTheDocument();
|
|
142
|
+
});
|
|
143
|
+
});
|
package/dist/config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export const API_BASE_URL =
|
|
2
|
-
import.meta.env.VITE_API_BASE_URL || 'https://get-micdrop.com';
|
|
3
|
-
|
|
4
|
-
export const PUBLIC_GOOGLE_MAPS_API_KEY =
|
|
5
|
-
import.meta.env.VITE_PUBLIC_GOOGLE_MAPS_API_KEY ||
|
|
1
|
+
export const API_BASE_URL =
|
|
2
|
+
import.meta.env.VITE_API_BASE_URL || 'https://get-micdrop.com';
|
|
3
|
+
|
|
4
|
+
export const PUBLIC_GOOGLE_MAPS_API_KEY =
|
|
5
|
+
import.meta.env.VITE_PUBLIC_GOOGLE_MAPS_API_KEY ||
|
|
6
6
|
'AIzaSyCFB0-9qay7P0jZZDw93SsTnyLtZDlch7Q';
|