From f4b56e0e8f31293206a126f16d7ca28aeabb900d Mon Sep 17 00:00:00 2001 From: Basar Buyukkahraman Date: Mon, 21 Nov 2022 00:34:30 +0300 Subject: [PATCH 1/5] Update component props with rerender --- src/__tests__/rerender.test.js | 24 ++---------------------- src/pure.js | 18 +++--------------- 2 files changed, 5 insertions(+), 37 deletions(-) diff --git a/src/__tests__/rerender.test.js b/src/__tests__/rerender.test.js index 2e1b423..665b333 100644 --- a/src/__tests__/rerender.test.js +++ b/src/__tests__/rerender.test.js @@ -2,30 +2,10 @@ import { render } from '..' import Comp from './fixtures/Comp' describe('rerender', () => { - test('mounts new component successfully', () => { + test('rerenders component with newly set prop', async () => { const { container, rerender } = render(Comp, { props: { name: 'World 1' } }) - expect(container.firstChild).toHaveTextContent('Hello World 1!') - rerender({ props: { name: 'World 2' } }) + await rerender({ props: { name: 'World 2' } }) expect(container.firstChild).toHaveTextContent('Hello World 2!') }) - - test('destroys old component', () => { - let isDestroyed - - const { rerender, component } = render(Comp, { props: { name: '' } }) - - component.$$.on_destroy.push(() => { isDestroyed = true }) - rerender({ props: { name: '' } }) - expect(isDestroyed).toBeTruthy() - }) - - test('destroys old components on multiple rerenders', () => { - const { rerender, queryByText } = render(Comp, { props: { name: 'Neil' } }) - - rerender({ props: { name: 'Alex' } }) - expect(queryByText('Hello Neil!')).not.toBeInTheDocument() - rerender({ props: { name: 'Geddy' } }) - expect(queryByText('Hello Alex!')).not.toBeInTheDocument() - }) }) diff --git a/src/pure.js b/src/pure.js index f9f1474..dc5aee0 100644 --- a/src/pure.js +++ b/src/pure.js @@ -70,21 +70,9 @@ const render = ( container, component, debug: (el = container) => console.log(prettyDOM(el)), - rerender: (options) => { - if (componentCache.has(component)) component.$destroy() - - // eslint-disable-next-line no-new - component = new ComponentConstructor({ - target, - ...checkProps(options), - }) - - containerCache.add({ container, target, component }) - componentCache.add(component) - - component.$$.on_destroy.push(() => { - componentCache.delete(component) - }) + rerender: async (options) => { + component.$set(options.props) + await tick() }, unmount: () => { if (componentCache.has(component)) component.$destroy() From b7f78eea7d2027ca720f071113b342bcfd29ba93 Mon Sep 17 00:00:00 2001 From: Basar Buyukkahraman Date: Mon, 21 Nov 2022 00:41:45 +0300 Subject: [PATCH 2/5] Update rerender return type --- types/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/index.d.ts b/types/index.d.ts index 9b688ed..1da5a2e 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -20,7 +20,7 @@ export type RenderResult void - rerender: (options: SvelteComponentOptions) => void + rerender: (options: SvelteComponentOptions) => Promise unmount: () => void } & { [P in keyof Q]: BoundFunction } From 8bf0f9689fed6038feccfb4dd3fcc2060bcb029e Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Sat, 3 Feb 2024 13:09:31 -0500 Subject: [PATCH 3/5] add rerender test --- src/__tests__/fixtures/Rerender.svelte | 15 +++++++++++++ src/__tests__/rerender.test.js | 30 ++++++++++++++++++-------- 2 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 src/__tests__/fixtures/Rerender.svelte diff --git a/src/__tests__/fixtures/Rerender.svelte b/src/__tests__/fixtures/Rerender.svelte new file mode 100644 index 0000000..aac1600 --- /dev/null +++ b/src/__tests__/fixtures/Rerender.svelte @@ -0,0 +1,15 @@ + + +

Hello {name}!

+ +
{$mountCounter}
diff --git a/src/__tests__/rerender.test.js b/src/__tests__/rerender.test.js index 6579271..d204089 100644 --- a/src/__tests__/rerender.test.js +++ b/src/__tests__/rerender.test.js @@ -1,16 +1,28 @@ /** * @jest-environment jsdom */ -import { describe, expect, test } from 'vitest' +import { expect, test } from 'vitest' +import { writable } from 'svelte/store' -import { render } from '..' -import Comp from './fixtures/Comp.svelte' +import { render, waitFor } from '..' +import Comp from './fixtures/Rerender.svelte' -describe('rerender', () => { - test('rerenders component with newly set prop', async () => { - const { container, rerender } = render(Comp, { props: { name: 'World 1' } }) - expect(container.firstChild).toHaveTextContent('Hello World 1!') - await rerender({ props: { name: 'World 2' } }) - expect(container.firstChild).toHaveTextContent('Hello World 2!') +const mountCounter = writable(0) + +test('mounts new component successfully', async () => { + const { getByTestId, rerender } = render(Comp, { + props: { name: 'World 1' }, + context: new Map(Object.entries({ mountCounter })), + }) + + await waitFor(() => { + expect(getByTestId('test')).toHaveTextContent('Hello World 1!') + expect(getByTestId('mount-counter')).toHaveTextContent('1') + }) + + rerender({ props: { name: 'World 2' } }) + await waitFor(() => { + expect(getByTestId('test')).toHaveTextContent('Hello World 2!') + expect(getByTestId('mount-counter')).toHaveTextContent('1') }) }) From ba6549a80f857124046c9a65f062a0d61befcbaa Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Mon, 12 Feb 2024 10:01:02 -0500 Subject: [PATCH 4/5] provide a warning for deprecated use --- src/__tests__/rerender.test.js | 28 +++++++++++++++++++--------- src/pure.js | 18 ++++++++++++------ 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/__tests__/rerender.test.js b/src/__tests__/rerender.test.js index d204089..d6cbc21 100644 --- a/src/__tests__/rerender.test.js +++ b/src/__tests__/rerender.test.js @@ -1,7 +1,7 @@ /** * @jest-environment jsdom */ -import { expect, test } from 'vitest' +import { expect, test, vi } from 'vitest' import { writable } from 'svelte/store' import { render, waitFor } from '..' @@ -15,14 +15,24 @@ test('mounts new component successfully', async () => { context: new Map(Object.entries({ mountCounter })), }) - await waitFor(() => { - expect(getByTestId('test')).toHaveTextContent('Hello World 1!') - expect(getByTestId('mount-counter')).toHaveTextContent('1') - }) + const expectToRender = (content) => + waitFor(() => { + expect(getByTestId('test')).toHaveTextContent(content) + expect(getByTestId('mount-counter')).toHaveTextContent('1') + }) + + await expectToRender('Hello World 1!') + + console.warn = vi.fn() rerender({ props: { name: 'World 2' } }) - await waitFor(() => { - expect(getByTestId('test')).toHaveTextContent('Hello World 2!') - expect(getByTestId('mount-counter')).toHaveTextContent('1') - }) + await expectToRender('Hello World 2!') + + expect(console.warn).toHaveBeenCalled() + + console.warn.mockClear() + rerender({ name: 'World 3' }) + await expectToRender('Hello World 3!') + + expect(console.warn).not.toHaveBeenCalled() }) diff --git a/src/pure.js b/src/pure.js index 59ee0ef..59c62ff 100644 --- a/src/pure.js +++ b/src/pure.js @@ -1,7 +1,7 @@ import { fireEvent as dtlFireEvent, getQueriesForElement, - prettyDOM + prettyDOM, } from '@testing-library/dom' import { tick } from 'svelte' @@ -14,7 +14,7 @@ const svelteComponentOptions = [ 'props', 'hydrate', 'intro', - 'context' + 'context', ] const render = ( @@ -56,7 +56,7 @@ const render = ( let component = new ComponentConstructor({ target, - ...checkProps(options) + ...checkProps(options), }) containerCache.add({ container, target, component }) @@ -70,14 +70,20 @@ const render = ( container, component, debug: (el = container) => console.log(prettyDOM(el)), - rerender: async (options) => { - component.$set(options.props) + rerender: async (props) => { + if (props.props) { + console.warn( + 'rerender({ props: {...} }) deprecated, use rerender({...}) instead' + ) + props = props.props + } + component.$set(props) await tick() }, unmount: () => { if (componentCache.has(component)) component.$destroy() }, - ...getQueriesForElement(container, queries) + ...getQueriesForElement(container, queries), } } From 4e18992479ab085d619cad1d1abd27fbcd486dcf Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Mon, 12 Feb 2024 10:11:47 -0500 Subject: [PATCH 5/5] prettier changes --- types/index.d.ts | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index 8d1f5cc..d60d779 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -2,25 +2,42 @@ // Project: https://github.com/testing-library/svelte-testing-library // Definitions by: Rahim Alwer -import {BoundFunction, EventType,Queries, queries} from '@testing-library/dom' -import { ComponentConstructorOptions,ComponentProps, SvelteComponent } from 'svelte' +import { + BoundFunction, + EventType, + Queries, + queries, +} from '@testing-library/dom' +import { + ComponentConstructorOptions, + ComponentProps, + SvelteComponent, +} from 'svelte' export * from '@testing-library/dom' -type SvelteComponentOptions = ComponentProps | Pick>, "anchor" | "props" | "hydrate" | "intro" | "context"> +type SvelteComponentOptions = + | ComponentProps + | Pick< + ComponentConstructorOptions>, + 'anchor' | 'props' | 'hydrate' | 'intro' | 'context' + > type Omit = Pick> -type Constructor = new (...args: any[]) => T; +type Constructor = new (...args: any[]) => T /** * Render a Component into the Document. */ -export type RenderResult = { +export type RenderResult< + C extends SvelteComponent, + Q extends Queries = typeof queries, +> = { container: HTMLElement component: C debug: (el?: HTMLElement | DocumentFragment) => void - rerender: (options: SvelteComponentOptions) => Promise + rerender: (props: ComponentProps) => Promise unmount: () => void } & { [P in keyof Q]: BoundFunction } @@ -38,7 +55,7 @@ export function render( export function render( component: Constructor, componentOptions?: SvelteComponentOptions, - renderOptions?: RenderOptions, + renderOptions?: RenderOptions ): RenderResult /** @@ -50,13 +67,19 @@ export function cleanup(): void * Fires DOM events on an element provided by @testing-library/dom. Since Svelte needs to flush * pending state changes via `tick`, these methods have been override and now return a promise. */ -export type FireFunction = (element: Document | Element | Window, event: Event) => Promise; +export type FireFunction = ( + element: Document | Element | Window, + event: Event +) => Promise export type FireObject = { - [K in EventType]: (element: Document | Element | Window, options?: {}) => Promise; -}; + [K in EventType]: ( + element: Document | Element | Window, + options?: {} + ) => Promise +} -export const fireEvent: FireFunction & FireObject; +export const fireEvent: FireFunction & FireObject /** * Calls a function and notifies Svelte to flush any pending state changes.