-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Add new PortingEmbed - Add safeguards that the embed is initialized with the correct data - Exchange session token with user token - Prefetch the subscription and ensure a supported porting is present - Renamed `lib/main.ts` to `lib/index.ts` because "main" is just another word for "index", and "index" is the more conventional name. - Add fixtures with [fishery](https://github.com/thoughtbot/fishery) for better testing
- Loading branch information
Showing
31 changed files
with
993 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Porting } from '../types' | ||
|
||
export type CustomizableEmbedProps = { | ||
// TODO: add styling options | ||
styleConfig?: { | ||
foo?: string | ||
} | ||
} | ||
|
||
type CoreEmbedProps = { | ||
token: string | ||
initialPorting: Porting | ||
} | ||
|
||
type PortingEmbedProps = CoreEmbedProps & CustomizableEmbedProps | ||
|
||
export function PortingEmbed({ token: _, initialPorting }: PortingEmbedProps) { | ||
return <div className="__gigsPortingEmbed">Hello {initialPorting.id}!</div> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Porting Embed | ||
|
||
## Usage | ||
|
||
```ts | ||
import { PortingEmbed } from '@gigs/gigs-embeds-js' | ||
|
||
// Obtain a ConnectSession from your own backend | ||
const connectSession = await fetchConnectSession() | ||
|
||
const embed = await PortingEmbed(connectSession, { project: 'your-project' }) | ||
embed.mount(document.getElementById('gigsEmbedMount')) | ||
|
||
// can also use a selector: | ||
// embed.mount('#gigsEmbedMount') | ||
|
||
// Here be more dragons | ||
|
||
// --- | ||
// index.html | ||
<div id="gigsEmbedMount"></div> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { portingFactory } from '@/testing/factories/porting' | ||
|
||
import { PortingEmbed } from '../PortingEmbed' | ||
|
||
export default { | ||
title: 'Porting Embed/Base', | ||
component: PortingEmbed, | ||
tags: ['autodocs'], | ||
argTypes: { | ||
token: { control: 'text' }, | ||
initialPorting: { control: 'object' }, | ||
}, | ||
} | ||
|
||
export const Primary = { | ||
args: { | ||
token: 'abc:123', | ||
initialPorting: portingFactory.build(), | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { render, screen } from '@testing-library/preact' | ||
|
||
import { portingFactory } from '@/testing/factories/porting' | ||
|
||
import { PortingEmbed } from '../PortingEmbed' | ||
|
||
it('gets the porting', () => { | ||
const porting = portingFactory.params({ id: 'prt_123' }).build() | ||
render(<PortingEmbed initialPorting={porting} token="abc:123" />) | ||
const greeting = screen.getByText(/Hello prt_123/i) | ||
expect(greeting).toBeInTheDocument() | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
import { render } from '@testing-library/preact' | ||
|
||
import { connectSessionFactory } from '@/testing/factories/connectSession' | ||
import { portingFactory } from '@/testing/factories/porting' | ||
import { subscriptionFactory } from '@/testing/factories/subscription' | ||
|
||
import { PortingStatus } from '../../types' | ||
import { PortingEmbed } from '../' | ||
|
||
const project = 'test_project' | ||
|
||
async function createFixtures() { | ||
const subscription = await subscriptionFactory.create() | ||
const connectSession = connectSessionFactory | ||
.completePorting(subscription.id) | ||
.build() | ||
return connectSession | ||
} | ||
|
||
beforeEach(() => { | ||
render(<div id="mount" />) | ||
}) | ||
|
||
describe('mounting', () => { | ||
it('mounts into a DOM selector', async () => { | ||
const csn = await createFixtures() | ||
const embed = await PortingEmbed(csn, { project }) | ||
|
||
embed.mount('#mount') | ||
expect(document.querySelector('.__gigsPortingEmbed')).toBeInTheDocument() | ||
}) | ||
|
||
it('mounts into a DOM element', async () => { | ||
const csn = await createFixtures() | ||
const embed = await PortingEmbed(csn, { project }) | ||
|
||
embed.mount(document.getElementById('mount')!) | ||
expect(document.querySelector('.__gigsPortingEmbed')).toBeInTheDocument() | ||
}) | ||
}) | ||
|
||
describe('updating', () => { | ||
it('updates the embed', async () => { | ||
const csn = await createFixtures() | ||
const embed = await PortingEmbed(csn, { project }) | ||
|
||
embed.mount('#mount') | ||
embed.update({}) | ||
expect(document.querySelector('.__gigsPortingEmbed')).toBeInTheDocument() | ||
}) | ||
|
||
it('fails to update an unmounted embed', async () => { | ||
const csn = await createFixtures() | ||
const embed = await PortingEmbed(csn, { project }) | ||
|
||
expect(() => embed.update({})).toThrow(/an unmounted embed/i) | ||
}) | ||
}) | ||
|
||
describe('unmounting', () => { | ||
it('unmounts the embed', async () => { | ||
const csn = await createFixtures() | ||
const embed = await PortingEmbed(csn, { project }) | ||
|
||
embed.mount('#mount') | ||
expect(document.getElementById('mount')).not.toBeEmptyDOMElement() | ||
embed.unmount() | ||
expect(document.getElementById('mount')).toBeEmptyDOMElement() | ||
}) | ||
|
||
it('fails to unmount an unmounted embed', async () => { | ||
const csn = await createFixtures() | ||
const embed = await PortingEmbed(csn, { project }) | ||
expect(() => embed.unmount()).toThrow(/an unmounted embed/i) | ||
}) | ||
}) | ||
|
||
describe('initialization', () => { | ||
it('initializes with valid data', async () => { | ||
const csn = await createFixtures() | ||
const embed = await PortingEmbed(csn, { project }) | ||
|
||
expect(embed.mount).toBeDefined() | ||
expect(embed.update).toBeDefined() | ||
expect(embed.unmount).toBeDefined() | ||
expect(embed.on).toBeDefined() | ||
expect(embed.off).toBeDefined() | ||
}) | ||
|
||
it('throws without a project', async () => { | ||
const csn = await createFixtures() | ||
// @ts-expect-error Assume the project is missing in a non-typechecked usage | ||
const init = PortingEmbed(csn, {}) | ||
expect(init).rejects.toThrow(/NO_PROJECT/) | ||
}) | ||
|
||
it('throws with the wrong ConnectSession', async () => { | ||
expect(PortingEmbed(null, { project })).rejects.toThrow(/INVALID_SESSION/) | ||
expect(PortingEmbed({}, { project })).rejects.toThrow(/INVALID_SESSION/) | ||
expect(PortingEmbed({ secret: 'foo' }, { project })).rejects.toThrow( | ||
/INVALID_SESSION/, | ||
) | ||
}) | ||
|
||
it('throws with a wrong intent', async () => { | ||
const csn = connectSessionFactory | ||
// @ts-expect-error Unsupported intent type | ||
.params({ intent: { type: 'foo' } }) | ||
.build() | ||
const init = PortingEmbed(csn, { project }) | ||
expect(init).rejects.toThrow(/INVALID_SESSION/) | ||
}) | ||
|
||
it('throws with a non-existing subscription', async () => { | ||
const csn = connectSessionFactory.completePorting('sub_404').build() | ||
const init = PortingEmbed(csn, { project }) | ||
expect(init).rejects.toThrow(/NOT_FOUND/) | ||
}) | ||
|
||
it('throws without a porting', async () => { | ||
const sub = await subscriptionFactory.withoutPorting().create() | ||
const csn = connectSessionFactory.completePorting(sub.id).build() | ||
const init = PortingEmbed(csn, { project }) | ||
expect(init).rejects.toThrow(/NOT_FOUND/) | ||
}) | ||
|
||
describe('with porting status', () => { | ||
async function createWithStatus(status: PortingStatus) { | ||
const porting = portingFactory.params({ status }).build() | ||
const subscription = await subscriptionFactory | ||
.associations({ porting }) | ||
.create() | ||
const connectSession = connectSessionFactory | ||
.completePorting(subscription.id) | ||
.build() | ||
return connectSession | ||
} | ||
|
||
it('initializes with informationRequired', async () => { | ||
const csn = await createWithStatus('informationRequired') | ||
const init = PortingEmbed(csn, { project }) | ||
expect(init).resolves.toBeDefined() | ||
}) | ||
|
||
it('initializes with declined', async () => { | ||
const csn = await createWithStatus('declined') | ||
const init = PortingEmbed(csn, { project }) | ||
expect(init).resolves.toBeDefined() | ||
}) | ||
|
||
it('throws with draft', async () => { | ||
const csn = await createWithStatus('draft') | ||
const init = PortingEmbed(csn, { project }) | ||
expect(init).rejects.toThrow(/UNSUPPORTED/) | ||
}) | ||
|
||
it('throws with requested', async () => { | ||
const csn = await createWithStatus('requested') | ||
const init = PortingEmbed(csn, { project }) | ||
expect(init).rejects.toThrow(/UNSUPPORTED/) | ||
}) | ||
|
||
it('throws with completed', async () => { | ||
const csn = await createWithStatus('completed') | ||
const init = PortingEmbed(csn, { project }) | ||
expect(init).rejects.toThrow(/UNSUPPORTED/) | ||
}) | ||
|
||
it('throws with canceled', async () => { | ||
const csn = await createWithStatus('canceled') | ||
const init = PortingEmbed(csn, { project }) | ||
expect(init).rejects.toThrow(/UNSUPPORTED/) | ||
}) | ||
|
||
it('throws with expired', async () => { | ||
const csn = await createWithStatus('expired') | ||
const init = PortingEmbed(csn, { project }) | ||
expect(init).rejects.toThrow(/UNSUPPORTED/) | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.