From 71a88533656812dcc7517d86610bff28f00748bd Mon Sep 17 00:00:00 2001 From: Sage Abdullah Date: Thu, 1 Feb 2024 23:56:27 +0100 Subject: [PATCH] Add tests for w-link --- client/src/controllers/LinkController.test.js | 429 ++++++++++++++++++ 1 file changed, 429 insertions(+) create mode 100644 client/src/controllers/LinkController.test.js diff --git a/client/src/controllers/LinkController.test.js b/client/src/controllers/LinkController.test.js new file mode 100644 index 0000000000..c8a60c7e01 --- /dev/null +++ b/client/src/controllers/LinkController.test.js @@ -0,0 +1,429 @@ +import { Application } from '@hotwired/stimulus'; +import { LinkController } from './LinkController'; + +describe('LinkController', () => { + let app; + const oldWindowLocation = window.location; + + const setWindowLocation = (url) => { + delete window.location; + window.location = new URL(url); + }; + + beforeEach(() => { + app = Application.start(); + app.register('w-link', LinkController); + }); + + afterEach(() => { + app?.stop(); + jest.clearAllMocks(); + window.location = oldWindowLocation; + }); + + describe('basic behaviour on connect', () => { + it('should reflect all params by default', async () => { + setWindowLocation( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok', + ); + expect(window.location.href).toEqual( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok', + ); + + document.body.innerHTML = ` + + Reflective link + + `; + + // Trigger next browser render cycle + await Promise.resolve(); + + // All params are reflected as-is, including multi-value and empty params + // and the relative URL is resolved against the current URL + expect(document.getElementById('link').href).toEqual( + 'http://localhost:8000/admin/something/?foo=bar&foo=baz&hello=&world=ok', + ); + // The current URL is not changed + expect(window.location.href).toEqual( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok', + ); + }); + + it('should only apply params in reflect-keys-value', async () => { + setWindowLocation( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok', + ); + expect(window.location.href).toEqual( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok', + ); + + document.body.innerHTML = ` + + Selectively reflective link + + `; + + // Trigger next browser render cycle + await Promise.resolve(); + + // Only the specified params are reflected + expect(document.getElementById('link').href).toEqual( + 'http://localhost:8000/admin/something/?foo=bar&foo=baz&hello=', + ); + // The current URL is not changed + expect(window.location.href).toEqual( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok', + ); + }); + + it('should preserve params in preserve-keys-value', async () => { + setWindowLocation( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok&a=z', + ); + expect(window.location.href).toEqual( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok&a=z', + ); + + document.body.innerHTML = ` + + Reflective link with preserve-keys-value + + `; + + // Trigger next browser render cycle + await Promise.resolve(); + + // Behaviour: + // - `export` param preserved (multi-value, not in new URL) + // - `foo` param preserved (single value, available in new URL) + // - `number` param not preserved (single value, not in new URL) + // - `hello` param reflected (empty value, only available in new URL) + // - `world` param reflected (single value, only available in new URL) + // - `a` param reflected (single value, available in both, taken from new URL) + expect(document.getElementById('link').href).toEqual( + 'http://localhost:8000/admin/something/?hello=&world=ok&a=z&export=xlsx&export=csv&foo=fii', + ); + // The current URL is not changed + expect(window.location.href).toEqual( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok&a=z', + ); + }); + + it('should reflect only the keys in reflect-keys-value and keep keys in preserve-keys-value', async () => { + setWindowLocation( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok&a=z', + ); + expect(window.location.href).toEqual( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok&a=z', + ); + + document.body.innerHTML = ` + + Reflective link with reflect-keys-value and preserve-keys-value + + `; + + // Trigger next browser render cycle + await Promise.resolve(); + + // Behaviour: + // - `export` param preserved (multi-value, not in new URL) + // - `foo` param preserved (single value, available in new URL) + // - `number` param not preserved (single value, not in new URL) + // - `hello` param reflected (empty value, only available in new URL) + // - `world` param not reflected (single value, only available in new URL) + // - `a` param reflected (single value, available in both, taken from new URL) + expect(document.getElementById('link').href).toEqual( + 'http://localhost:8000/admin/something/?hello=&a=z&export=xlsx&export=csv&foo=fii', + ); + // The current URL is not changed + expect(window.location.href).toEqual( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok&a=z', + ); + }); + }); + + describe('handling an event with requestUrl in the detail', () => { + it('should reflect all params by default', async () => { + expect(window.location.href).toEqual('http://localhost/'); + + document.body.innerHTML = ` + + Reflective link + + `; + + // Trigger next browser render cycle + await Promise.resolve(); + + document.dispatchEvent( + new CustomEvent('w-swap:reflect', { + detail: { + requestUrl: + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok', + }, + }), + ); + + // All params are reflected as-is, including multi-value and empty params + // and the relative URL is resolved against the current URL + expect(document.getElementById('link').href).toEqual( + 'http://localhost/admin/something/?foo=bar&foo=baz&hello=&world=ok', + ); + }); + + it('should only apply params in reflect-keys-value', async () => { + expect(window.location.href).toEqual('http://localhost/'); + + document.body.innerHTML = ` + + Selectively reflective link + + `; + + // Trigger next browser render cycle + await Promise.resolve(); + + document.dispatchEvent( + new CustomEvent('w-swap:reflect', { + detail: { + requestUrl: + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok', + }, + }), + ); + + // Only the specified params are reflected + expect(document.getElementById('link').href).toEqual( + 'http://localhost/admin/something/?foo=bar&foo=baz&hello=', + ); + }); + + it('should preserve params in preserve-keys-value', async () => { + expect(window.location.href).toEqual('http://localhost/'); + + document.body.innerHTML = ` + + Reflective link with preserve-keys-value + + `; + + // Trigger next browser render cycle + await Promise.resolve(); + + document.dispatchEvent( + new CustomEvent('w-swap:reflect', { + detail: { + requestUrl: + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok&a=z', + }, + }), + ); + + // Behaviour: + // - `export` param preserved (multi-value, not in new URL) + // - `foo` param preserved (single value, available in new URL) + // - `number` param not preserved (single value, not in new URL) + // - `hello` param reflected (empty value, only available in new URL) + // - `world` param reflected (single value, only available in new URL) + // - `a` param reflected (single value, available in both, taken from new URL) + expect(document.getElementById('link').href).toEqual( + 'http://localhost/admin/something/?hello=&world=ok&a=z&export=xlsx&export=csv&foo=fii', + ); + }); + + it('should reflect only the keys in reflect-keys-value and keep keys in preserve-keys-value', async () => { + expect(window.location.href).toEqual('http://localhost/'); + + document.body.innerHTML = ` + + Reflective link with reflect-keys-value and preserve-keys-value + + `; + + // Trigger next browser render cycle + await Promise.resolve(); + + document.dispatchEvent( + new CustomEvent('w-swap:reflect', { + detail: { + requestUrl: + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok&a=z', + }, + }), + ); + + // Behaviour: + // - `export` param preserved (multi-value, not in new URL) + // - `foo` param preserved (single value, available in new URL) + // - `number` param not preserved (single value, not in new URL) + // - `hello` param reflected (empty value, only available in new URL) + // - `world` param not reflected (single value, only available in new URL) + // - `a` param reflected (single value, available in both, taken from new URL) + expect(document.getElementById('link').href).toEqual( + 'http://localhost/admin/something/?hello=&a=z&export=xlsx&export=csv&foo=fii', + ); + }); + }); + + describe('handling an event without requestUrl in the detail', () => { + it('should not reflect any params', async () => { + expect(window.location.href).toEqual('http://localhost/'); + + document.body.innerHTML = ` + + Reflective link + + `; + + // Trigger next browser render cycle + await Promise.resolve(); + + document.dispatchEvent( + new CustomEvent('custom:event', { + detail: { + something: 'else', + }, + }), + ); + + // Should not change the href + expect(document.getElementById('link').href).toEqual( + 'http://localhost/admin/something/', + ); + }); + }); + + describe('using a custom attr-name-value for the link', () => { + it('should reflect the params from the current URL to the link in the specified attribute', async () => { + setWindowLocation( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok&a=z', + ); + expect(window.location.href).toEqual( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok&a=z', + ); + + document.body.innerHTML = ` + + `; + + // Trigger next browser render cycle + await Promise.resolve(); + + // Behaviour: + // - `export` param preserved (multi-value, not in new URL) + // - `foo` param preserved (single value, available in new URL) + // - `number` param not preserved (single value, not in new URL) + // - `hello` param reflected (empty value, only available in new URL) + // - `world` param not reflected (single value, only available in new URL) + // - `a` param reflected (single value, available in both, taken from new URL) + expect(document.getElementById('button').dataset.targetUrl).toEqual( + 'http://localhost:8000/admin/something/?hello=&a=z&export=xlsx&export=csv&foo=fii', + ); + // The current URL is not changed + expect(window.location.href).toEqual( + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok&a=z', + ); + }); + + it("should reflect the params from the event's requestUrl to the link in the specified attribute", async () => { + expect(window.location.href).toEqual('http://localhost/'); + + document.body.innerHTML = ` + + `; + + // Trigger next browser render cycle + await Promise.resolve(); + + document.dispatchEvent( + new CustomEvent('w-swap:reflect', { + detail: { + requestUrl: + 'http://localhost:8000/admin/pages/?foo=bar&foo=baz&hello=&world=ok&a=z', + }, + }), + ); + + // Behaviour: + // - `export` param preserved (multi-value, not in new URL) + // - `foo` param preserved (single value, available in new URL) + // - `number` param not preserved (single value, not in new URL) + // - `hello` param reflected (empty value, only available in new URL) + // - `world` param not reflected (single value, only available in new URL) + // - `a` param reflected (single value, available in both, taken from new URL) + expect(document.getElementById('button').dataset.targetUrl).toEqual( + 'http://localhost/admin/something/?hello=&a=z&export=xlsx&export=csv&foo=fii', + ); + }); + }); +});