diff --git a/app/Http/Controllers/API/SongController.php b/app/Http/Controllers/API/SongController.php index 02c481b0..ec8b2bf1 100644 --- a/app/Http/Controllers/API/SongController.php +++ b/app/Http/Controllers/API/SongController.php @@ -38,7 +38,7 @@ class SongController extends Controller $this->songRepository->getForListing( sortColumn: $request->sort ?: 'songs.title', sortDirection: $request->order ?: 'asc', - ownSongsOnly: (bool) $request->ownSongsOnly, + ownSongsOnly: $request->boolean('own_songs_only'), scopedUser: $this->user ) ); diff --git a/app/Http/Requests/API/SongListRequest.php b/app/Http/Requests/API/SongListRequest.php index 1de5f234..039984d1 100644 --- a/app/Http/Requests/API/SongListRequest.php +++ b/app/Http/Requests/API/SongListRequest.php @@ -5,7 +5,7 @@ namespace App\Http\Requests\API; /** * @property-read string $order * @property-read string $sort - * @property-read boolean|string|integer $ownSongsOnly + * @property-read boolean|string|integer $own_songs_only */ class SongListRequest extends Request { diff --git a/resources/assets/js/__tests__/UnitTestCase.ts b/resources/assets/js/__tests__/UnitTestCase.ts index 8ddf7121..be69ee11 100644 --- a/resources/assets/js/__tests__/UnitTestCase.ts +++ b/resources/assets/js/__tests__/UnitTestCase.ts @@ -52,21 +52,22 @@ export default abstract class UnitTestCase { protected afterEach (cb?: Closure) { afterEach(() => { + isMobile.any = false commonStore.state.song_length = 10 cleanup() this.restoreAllMocks() - isMobile.any = false + this.disablePlusEdition() cb && cb() }) } - protected actingAs (user?: User) { + protected be (user?: User) { userStore.state.current = user || factory('user') return this } - protected actingAsAdmin () { - return this.actingAs(factory.states('admin')('user')) + protected beAdmin () { + return this.be(factory.states('admin')('user')) } protected mock>> (obj: T, methodName: M, implementation?: any) { @@ -137,6 +138,26 @@ export default abstract class UnitTestCase { return options } + protected enablePlusEdition () { + commonStore.state.koel_plus = { + active: true, + short_key: '****-XXXX', + customer_name: 'John Doe', + customer_email: 'Koel Plus', + product_id: 'koel-plus', + } + } + + protected disablePlusEdition () { + commonStore.state.koel_plus = { + active: false, + short_key: '', + customer_name: '', + customer_email: '', + product_id: '', + } + } + protected stub (testId = 'stub') { return defineComponent({ template: `
` diff --git a/resources/assets/js/__tests__/setup.ts b/resources/assets/js/__tests__/setup.ts index 6069f3ad..dcde7793 100644 --- a/resources/assets/js/__tests__/setup.ts +++ b/resources/assets/js/__tests__/setup.ts @@ -1,13 +1,20 @@ -declare global { - interface Window { - BASE_URL: string; - } -} - import vueSnapshotSerializer from 'jest-serializer-vue' import { expect, vi } from 'vitest' import Axios from 'axios' +declare global { + interface Window { + BASE_URL: string; + createLemonSqueezy: () => void; + } + + interface LemonSqueezy { + Url: { + Open: () => void; + } + } +} + expect.addSnapshotSerializer(vueSnapshotSerializer) global.ResizeObserver = global.ResizeObserver || @@ -17,6 +24,13 @@ global.ResizeObserver = global.ResizeObserver || unobserve: vi.fn() })) + +global.LemonSqueezy = { + Url: { + Open: vi.fn() + } +} + HTMLMediaElement.prototype.load = vi.fn() HTMLMediaElement.prototype.play = vi.fn() HTMLMediaElement.prototype.pause = vi.fn() @@ -34,5 +48,6 @@ HTMLDialogElement.prototype.close = vi.fn(function mock () { }) window.BASE_URL = 'http://test/' +window.createLemonSqueezy = vi.fn() Axios.defaults.adapter = vi.fn() diff --git a/resources/assets/js/components/koel-plus/ActivateLicenseForm.spec.ts b/resources/assets/js/components/koel-plus/ActivateLicenseForm.spec.ts new file mode 100644 index 00000000..9bc8171d --- /dev/null +++ b/resources/assets/js/components/koel-plus/ActivateLicenseForm.spec.ts @@ -0,0 +1,22 @@ +import { screen } from '@testing-library/vue' +import { expect, it } from 'vitest' +import UnitTestCase from '@/__tests__/UnitTestCase' +import { plusService } from '@/services' +import Form from './ActivateLicenseForm.vue' + +new class extends UnitTestCase { + private renderComponent () { + return this.render(Form ) + } + + protected test () { + it('activates license', async () => { + this.renderComponent() + const activateMock = this.mock(plusService, 'activateLicense').mockResolvedValueOnce('') + + await this.type(screen.getByRole('textbox'), 'my-license-key') + await this.user.click(screen.getByText('Activate')) + expect(activateMock).toHaveBeenCalledWith('my-license-key') + }) + } +} diff --git a/resources/assets/js/components/koel-plus/KoelPlusModal.spec.ts b/resources/assets/js/components/koel-plus/KoelPlusModal.spec.ts new file mode 100644 index 00000000..88c8a681 --- /dev/null +++ b/resources/assets/js/components/koel-plus/KoelPlusModal.spec.ts @@ -0,0 +1,32 @@ +import { screen } from '@testing-library/vue' +import { commonStore } from '@/stores' +import { expect, it } from 'vitest' +import UnitTestCase from '@/__tests__/UnitTestCase' +import Modal from './KoelPlusModal.vue' + +new class extends UnitTestCase { + private renderComponent () { + return this.render(Modal) + } + + protected test () { + it('shows button to purchase Koel Plus', async () => { + commonStore.state.koel_plus.product_id = '42' + this.renderComponent() + + screen.getByTestId('buttons') + expect(screen.queryByTestId('activateForm')).toBeNull() + await this.user.click(screen.getByText('Purchase Koel Plus')) + expect(global.LemonSqueezy.Url.Open).toHaveBeenCalledWith( + 'https://store.plus.koel.dev/checkout/buy/42?embed=1&media=0&desc=0' + ) + }) + + it('shows form to activate Koel Plus', async () => { + commonStore.state.koel_plus.product_id = '42' + this.renderComponent() + await this.user.click(screen.getByText('I have a license key')) + screen.getByTestId('activateForm') + }) + } +} diff --git a/resources/assets/js/components/koel-plus/KoelPlusModal.vue b/resources/assets/js/components/koel-plus/KoelPlusModal.vue index 119247e5..f184d536 100644 --- a/resources/assets/js/components/koel-plus/KoelPlusModal.vue +++ b/resources/assets/js/components/koel-plus/KoelPlusModal.vue @@ -9,12 +9,12 @@ in the future! -
+
Purchase Koel Plus I have a license key
-
+
Cancel
@@ -52,7 +52,7 @@ const openPurchaseOverlay = () => { const showActivateLicenseForm = () => (showingActivateLicenseForm.value = true) const hideActivateLicenseForm = () => (showingActivateLicenseForm.value = false) -onMounted(() => window.createLemonSqueezy()) // @ts-ignore +onMounted(() => window.createLemonSqueezy?.())