Skip to content

Commit

Permalink
feat: new lifecycle properties
Browse files Browse the repository at this point in the history
  • Loading branch information
sastan committed Jun 22, 2020
1 parent 8218908 commit f2b070b
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 3 deletions.
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,69 @@ And then grab it off the global like so:
```js
const Fragment = svelteFragment
```

## Usage

> The examples below are using [svelte-jsx](https://www.npmjs.com/package/svelte-jsx) for the jsx syntax support.
```js
import Fragment from 'svelte-fragment-component'

const Lifecycle = (
<Fragment
onCreate={() => {}}
onMount={() => {}}
beforeUpdate={() => {}}
afterUpdate={() => {}}
onDestroy={() => {}}
>
some content
</Fragment>
)
```

This allows to simplify testing of [context API](https://svelte.dev/docs#setContext):

```js
import Fragment from 'svelte-fragment-component'
import { setContext } from 'svelte'

const Lifecycle = (
<Fragment
onCreate={() => {
setContext('some context key', theValue)
}}
>
children can now access this context value
</Fragment>
)

// or using the context property
const Lifecycle = (
<Fragment context={{ 'some context key': theValue }}>
children can now access this context value
</Fragment>
)
```

## API

The component renders only the default slot children.

### Properties

> All properties are optional.
- `context`: an key-value object where each pair is passed to [setContext](https://svelte.dev/docs#setContext)

Except for `onCreate` these functions are passed to their corresponding svelte lifecycle method and have the same call signature `({ props }): void` where `props` are the `$$restProps`:

- `onCreate`: called during component initialization
- [onMount](https://svelte.dev/docs#onMount)
- [beforeUpdate](https://svelte.dev/docs#beforeUpdate)
- [afterUpdate](https://svelte.dev/docs#afterUpdate)
- [onDestroy](https://svelte.dev/docs#onDestroy)

## Support

This project is free and open-source, so if you think this project can help you or anyone else, you may [star it on GitHub](https://github.com/sastan/svelte-fragment-component). Feel free to [open an issue](https://github.com/sastan/svelte-fragment-component/issues) if you have any idea, question, or you've found a bug.
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
},
"homepage": "https://github.com/sastan/svelte-fragment-component#readme",
"devDependencies": {
"@jest/globals": "^26.0.1",
"@rollup/plugin-commonjs": "^13.0.0",
"@rollup/plugin-node-resolve": "^8.0.1",
"@testing-library/jest-dom": "^5.7.0",
Expand Down
28 changes: 28 additions & 0 deletions src/fragment.svelte
Original file line number Diff line number Diff line change
@@ -1 +1,29 @@
<script>
import * as Svelte from 'svelte'
export let context = null
export let onCreate = null
export let onMount = null
export let beforeUpdate = null
export let afterUpdate = null
export let onDestroy = null
if (context) {
Object.keys(context).forEach((key) => {
Svelte.setContext(key, context[key])
})
}
if (onCreate) bind(onCreate)()
if (onMount) Svelte.onMount(bind(onMount))
if (beforeUpdate) Svelte.beforeUpdate(bind(beforeUpdate))
if (afterUpdate) Svelte.afterUpdate(bind(afterUpdate))
if (onDestroy) Svelte.onDestroy(bind(onDestroy))
function bind(callback) {
return () => callback({ props: $$restProps })
}
</script>

<slot></slot>
73 changes: 71 additions & 2 deletions src/fragment.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,79 @@
const { expect, test } = require('@jest/globals')
const { render } = require('@testing-library/svelte')
const { render, act } = require('@testing-library/svelte')
const { getContext } = require('svelte')

const WithChilds = require('./__fixtures__/with-childs.svelte')
const Fragment = require('./fragment.svelte')

test('renders all childs', () => {
const { container } = render(WithChilds)

expect(container.innerHTML).toMatch('<div>A<span>B</span>C</div>')
})

test('calls onCreate', () => {
const onCreate = jest.fn()

render(Fragment, { props: { onCreate, a: 1 } })

expect(onCreate).toHaveBeenCalledWith({ props: { a: 1 } })
})

test('calls onMount', () => {
const onMount = jest.fn()

render(Fragment, { props: { onMount, a: 1 } })

expect(onMount).toHaveBeenCalledWith({ props: { a: 1 } })
})

test('calls beforeUpdate', async () => {
const beforeUpdate = jest.fn()

const { component } = render(Fragment, { props: { beforeUpdate, a: 1 } })

expect(beforeUpdate).toHaveBeenCalledWith({ props: { a: 1 } })

await act(() => component.$set({ b: 2 }))

expect(beforeUpdate).toHaveBeenCalledWith({ props: { a: 1, b: 2 } })
})

test('calls afterUpdate', async () => {
const afterUpdate = jest.fn()

const { component } = render(Fragment, { props: { afterUpdate, a: 1 } })

expect(afterUpdate).toHaveBeenCalledWith({ props: { a: 1 } })

await act(() => component.$set({ b: 2 }))

expect(afterUpdate).toHaveBeenCalledWith({ props: { a: 1, b: 2 } })
})

test('calls onDestroy', async () => {
const onDestroy = jest.fn()

const { component } = render(Fragment, { props: { onDestroy, a: 1 } })

await act(() => component.$destroy())

expect(onDestroy).toHaveBeenCalledWith({ props: { a: 1 } })
})

test('create context', () => {
let a
let b

render(Fragment, {
props: {
context: { a: 1, b: 2 },
onMount: () => {
a = getContext('a')
b = getContext('b')
},
},
})

expect(a).toBe(1)
expect(b).toBe(2)
})

0 comments on commit f2b070b

Please sign in to comment.