Skip to content

Commit

Permalink
Merge pull request #122 from blutui/feat-cassettes
Browse files Browse the repository at this point in the history
feat: Add Cassettes resource
  • Loading branch information
chengfang-blutui authored Dec 3, 2024
2 parents 47dfdd3 + 2e05703 commit f0edfab
Show file tree
Hide file tree
Showing 22 changed files with 412 additions and 6 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true
},
"typescript.tsdk": "node_modules/typescript/lib"
"typescript.tsdk": "node_modules/typescript/lib",
"explorer.fileNesting.enabled": true
}
9 changes: 5 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/agency.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Brand,
Cassettes,
Domains,
Invites,
Members,
Expand All @@ -12,6 +13,7 @@ import type { GetOptions, PostOptions } from './types'

export class Agency {
readonly brand = new Brand(this)
readonly cassettes = new Cassettes(this)
readonly domains = new Domains(this)
readonly invites = new Invites(this)
readonly members = new Members(this)
Expand Down
101 changes: 101 additions & 0 deletions src/resources/agency/cassettes/cassettes.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import fetch from 'jest-fetch-mock'
import { Blutui } from '@/blutui'
import { fetchOnce, fetchURL } from '@/utils/testing'

import cassetteFixture from './fixtures/cassette.json'

const accessToken =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
const blutui = new Blutui(accessToken)

describe('Cassette', () => {
beforeEach(() => fetch.resetMocks())

describe('get', () => {
it('can retireve a cassette', async () => {
fetchOnce(cassetteFixture)
const cassette = await blutui
.agency('foo')
.cassettes.get(cassetteFixture.id)

expect(fetchURL()).toBe(
`${blutui.baseURL}/v1/agencies/foo/cassettes/${cassetteFixture.id}`
)
expect(cassette).toMatchObject({
object: 'cassette',
})
})
})

describe('create', () => {
it('can create a new cassette', async () => {
fetchOnce(cassetteFixture)
const cassette = await blutui.agency('foo').cassettes.create({
handle: 'default',
name: 'Default',
project: 'project-id',
})

expect(fetchURL()).toBe(`${blutui.baseURL}/v1/agencies/foo/cassettes`)
expect(cassette).toMatchObject({
object: 'cassette',
name: 'Default',
})
})
})

describe('update', () => {
it('can update an existing cassette', async () => {
fetchOnce(cassetteFixture)
const cassette = await blutui
.agency('foo')
.cassettes.update(cassetteFixture.id, {
name: 'Default',
})

expect(fetchURL()).toBe(
`${blutui.baseURL}/v1/agencies/foo/cassettes/${cassetteFixture.id}`
)
expect(cassette).toMatchObject({
object: 'cassette',
name: 'Default',
})
})
})

describe('remove', () => {
it('can remove a cassette', async () => {
fetchOnce({ id: cassetteFixture.id, object: 'cassette', deleted: true })
const cassette = await blutui
.agency('foo')
.cassettes.remove(cassetteFixture.id)

expect(fetchURL()).toBe(
`${blutui.baseURL}/v1/agencies/foo/cassettes/${cassetteFixture.id}`
)
expect(cassette).toMatchObject({
object: 'cassette',
deleted: true,
})
})
})

describe('duplicate', () => {
it('can duplicate an existing cassette', async () => {
fetchOnce(cassetteFixture)
const cassette = await blutui
.agency('foo')
.cassettes.duplicate(cassetteFixture.id, {
name: 'Default',
handle: 'default',
})

expect(fetchURL()).toBe(
`${blutui.baseURL}/v1/agencies/foo/cassettes/${cassetteFixture.id}/duplicate`
)
expect(cassette).toMatchObject({
object: 'cassette',
})
})
})
})
87 changes: 87 additions & 0 deletions src/resources/agency/cassettes/cassettes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import {
deserializeCassette,
serializeCreateCassetteOptions,
serializeDuplicateCassetteOptions,
serializeUpdateCassetteOptions,
} from './serializers'

import type { Agency } from '@/agency'
import type {
CassetteResponse,
Cassette,
CreateCassetteOptions,
SerializedCreateCassetteOptions,
UpdateCassetteOptions,
SerializedUpdateCassetteOptions,
DuplicateCassetteOptions,
SerializedDuplicateCassetteOptions,
} from './interfaces'
import type { DeletedResponse, Expandable } from '@/types'

export class Cassettes {
constructor(private readonly agency: Agency) {}

/**
* Retrieve a Cassette by ID.
*/
async get(id: string, options?: Expandable<'project'>): Promise<Cassette> {
const { data } = await this.agency.get<CassetteResponse>(
`cassettes/${id}`,
{
query: options,
}
)

return deserializeCassette(data)
}

/**
* Create a new Cassette for a project your agency..
*/
async create(payload: CreateCassetteOptions): Promise<Cassette> {
const { data } = await this.agency.post<
CassetteResponse,
SerializedCreateCassetteOptions
>('cassettes', serializeCreateCassetteOptions(payload))

return deserializeCassette(data)
}

/**
* Update a Cassette by ID.
*/
async update(id: string, payload: UpdateCassetteOptions): Promise<Cassette> {
const { data } = await this.agency.patch<
CassetteResponse,
SerializedUpdateCassetteOptions
>(`cassettes/${id}`, serializeUpdateCassetteOptions(payload))

return deserializeCassette(data)
}

/**
* Remove a Cassette from a project in your agency.
*/
async remove(id: string): Promise<DeletedResponse> {
const { data } = await this.agency.delete<DeletedResponse>(
`cassettes/${id}`
)

return data
}

/**
* Duplicate a Cassette for a project your agency.
*/
async duplicate(
id: string,
payload: DuplicateCassetteOptions
): Promise<Cassette> {
const { data } = await this.agency.post<
CassetteResponse,
SerializedDuplicateCassetteOptions
>(`cassettes/${id}/duplicate`, serializeDuplicateCassetteOptions(payload))

return deserializeCassette(data)
}
}
24 changes: 24 additions & 0 deletions src/resources/agency/cassettes/fixtures/cassette-list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"object": "list",
"data": [
{
"id": "9d759f5a-7a1f-443e-a466-6471da1d367b",
"object": "cassette",
"handle": "default",
"name": "Default",
"project": "9c17d63b-96c0-4315-b4dd-e55373ce4ffd",
"parent": null,
"created_at": 1711305486,
"updated_at": 1711305486
}
],
"meta": {
"hasMore": false,
"currentPage": 1,
"from": 1,
"to": 1,
"perPage": 10,
"total": 1,
"lastPage": 1
}
}
10 changes: 10 additions & 0 deletions src/resources/agency/cassettes/fixtures/cassette.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"id": "9d759f5a-7a1f-443e-a466-6471da1d367b",
"object": "cassette",
"handle": "default",
"name": "Default",
"project": "9c17d63b-96c0-4315-b4dd-e55373ce4ffd",
"parent": null,
"created_at": 1711305486,
"updated_at": 1711305486
}
23 changes: 23 additions & 0 deletions src/resources/agency/cassettes/interfaces/cassette.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { Project, ProjectResponse } from '../../projects/interfaces'

export interface Cassette {
id: string
object: 'cassette'
handle: string
name: string
project: string | Project | null
parent: string | Cassette | null
createdAt: number
updatedAt: number
}

export interface CassetteResponse {
id: string
object: 'cassette'
handle: string
name: string
project: string | ProjectResponse | null
parent: string | CassetteResponse | null
created_at: number
updated_at: number
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface CreateCassetteOptions {
name: string
project: string
handle: string
}

export interface SerializedCreateCassetteOptions {
name: string
project: string
handle: string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface DuplicateCassetteOptions {
handle: string
name: string
}

export interface SerializedDuplicateCassetteOptions {
handle: string
name: string
}
4 changes: 4 additions & 0 deletions src/resources/agency/cassettes/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './cassette.interface'
export * from './create-cassette-options.interface'
export * from './duplicate-cassette-options.interface'
export * from './update-cassette-options.interface'
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface UpdateCassetteOptions {
name: string
}

export interface SerializedUpdateCassetteOptions {
name: string
}
30 changes: 30 additions & 0 deletions src/resources/agency/cassettes/serializers/cassette.serializer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { deserializeProject } from '../../projects/serializers'

import type { List, ListResponse } from '@/types'
import type { Cassette, CassetteResponse } from '../interfaces'
import { deserializePaginationMeta } from '@/utils/serializers'

export const deserializeCassette = (cassette: CassetteResponse): Cassette => ({
id: cassette.id,
object: cassette.object,
handle: cassette.handle,
name: cassette.name,
project:
cassette.project instanceof Object
? deserializeProject(cassette.project)
: cassette.project,
parent:
cassette.parent instanceof Object
? deserializeCassette(cassette.parent)
: cassette.parent,
createdAt: cassette.created_at,
updatedAt: cassette.updated_at,
})

export const deserializeCassetteList = (
cassettes: ListResponse<CassetteResponse>
): List<Cassette> => ({
object: cassettes.object,
data: cassettes.data.map(deserializeCassette),
meta: deserializePaginationMeta(cassettes.meta),
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type {
CreateCassetteOptions,
SerializedCreateCassetteOptions,
} from '../interfaces'

export const serializeCreateCassetteOptions = (
options: CreateCassetteOptions
): SerializedCreateCassetteOptions => ({
handle: options.handle,
name: options.name,
project: options.project,
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type {
DuplicateCassetteOptions,
SerializedDuplicateCassetteOptions,
} from '../interfaces'

export const serializeDuplicateCassetteOptions = (
options: DuplicateCassetteOptions
): SerializedDuplicateCassetteOptions => ({
handle: options.handle,
name: options.name,
})
4 changes: 4 additions & 0 deletions src/resources/agency/cassettes/serializers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './cassette.serializer'
export * from './create-cassette-options.serializer'
export * from './duplicate-cassette-options.serializer'
export * from './update-cassette-options.serializer'
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type {
SerializedUpdateCassetteOptions,
UpdateCassetteOptions,
} from '../interfaces'

export const serializeUpdateCassetteOptions = (
options: UpdateCassetteOptions
): SerializedUpdateCassetteOptions => ({
name: options.name,
})
Loading

0 comments on commit f0edfab

Please sign in to comment.