Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add editor extension collection spec #3551

Merged
merged 1 commit into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/app/src/cli/models/extensions/load-specifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import taxCalculationSpec from './specifications/tax_calculation.js'
import themeSpec from './specifications/theme.js'
import uiExtensionSpec from './specifications/ui_extension.js'
import webPixelSpec from './specifications/web_pixel_extension.js'
import editorExtensionCollectionSpecification from './specifications/editor_extension_collection.js'

const SORTED_CONFIGURATION_SPEC_IDENTIFIERS = [
BrandingSpecIdentifier,
Expand Down Expand Up @@ -66,6 +67,7 @@ function loadSpecifications() {
themeSpec,
uiExtensionSpec,
webPixelSpec,
editorExtensionCollectionSpecification,
] as ExtensionSpecification[]

return [...configModuleSpecs, ...moduleSpecs]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import {ExtensionInstance} from '../extension-instance.js'
import {loadLocalExtensionsSpecifications} from '../load-specifications.js'
import {DeveloperPlatformClient} from '../../../utilities/developer-platform-client.js'
import {testDeveloperPlatformClient} from '../../app/app.test-data.js'
import {inTemporaryDirectory} from '@shopify/cli-kit/node/fs'
import {joinPath} from '@shopify/cli-kit/node/path'
import {describe, expect, test} from 'vitest'

const developerPlatformClient: DeveloperPlatformClient = testDeveloperPlatformClient()

describe('editor_extension_collection', async () => {
interface EditorExtensionCollectionProps {
directory: string
configuration: {name: string; handle: string; includes?: string[]; include?: {handle: string}[]}
}

async function getTestEditorExtensionCollection({
directory,
configuration: passedConfig,
}: EditorExtensionCollectionProps) {
const configurationPath = joinPath(directory, 'shopify.extension.toml')
const allSpecs = await loadLocalExtensionsSpecifications()
const specification = allSpecs.find((spec) => spec.identifier === 'editor_extension_collection')!
const configuration = {
...passedConfig,
type: 'editor_extension_collection',
metafields: [],
}

return new ExtensionInstance({
configuration,
directory,
specification,
configurationPath,
entryPath: '',
})
}

describe('deployConfig()', () => {
test('returns the deploy config when includes and include is passed in', async () => {
await inTemporaryDirectory(async (tmpDir) => {
const configuration = {
name: 'Order summary',
handle: 'order-summary-collection',
includes: ['handle1'],
include: [
{
handle: 'handle2',
},
],
}
const extensionCollection = await getTestEditorExtensionCollection({
directory: tmpDir,
configuration,
})

const deployConfig = await extensionCollection.deployConfig({
apiKey: 'apiKey',
developerPlatformClient,
})

expect(deployConfig).toStrictEqual({
name: extensionCollection.configuration.name,
handle: extensionCollection.configuration.handle,
in_collection: [{handle: 'handle1'}, {handle: 'handle2'}],
})
})
})

test('returns the deploy config when only include is passed in', async () => {
await inTemporaryDirectory(async (tmpDir) => {
const configuration = {
name: 'Order summary',
handle: 'order-summary-collection',
include: [
{
handle: 'handle2',
},
],
}
const extensionCollection = await getTestEditorExtensionCollection({
directory: tmpDir,
configuration,
})

const deployConfig = await extensionCollection.deployConfig({
apiKey: 'apiKey',
developerPlatformClient,
})

expect(deployConfig).toStrictEqual({
name: extensionCollection.configuration.name,
handle: extensionCollection.configuration.handle,
in_collection: [{handle: 'handle2'}],
})
})
})

test('returns the deploy config when only includes is passed in', async () => {
await inTemporaryDirectory(async (tmpDir) => {
const configuration = {
name: 'Order summary',
handle: 'order-summary-collection',
includes: ['handle1'],
}
const extensionCollection = await getTestEditorExtensionCollection({
directory: tmpDir,
configuration,
})

const deployConfig = await extensionCollection.deployConfig({
apiKey: 'apiKey',
developerPlatformClient,
})

expect(deployConfig).toStrictEqual({
name: extensionCollection.configuration.name,
handle: extensionCollection.configuration.handle,
in_collection: [{handle: 'handle1'}],
})
})
})
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {BaseSchema} from '../schemas.js'
import {createExtensionSpecification} from '../specification.js'
import {zod} from '@shopify/cli-kit/node/schema'

interface IncludeSchema {
handle: string
}

const IncludeSchema = zod.object({
handle: zod.string(),
})

export const EditorExtensionCollectionSchema = BaseSchema.extend({
include: zod.array(IncludeSchema).optional(),
Copy link
Contributor Author

@oluwatimio oluwatimio Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both optional so you can use either one of them without needing to declare the other. We will add validation to make sure at least one of them exists

includes: zod.array(zod.string()).optional(),
type: zod.literal('editor_extension_collection'),
})

const editorExtensionCollectionSpecification = createExtensionSpecification({
identifier: 'editor_extension_collection',
schema: EditorExtensionCollectionSchema,
appModuleFeatures: (_) => [],
deployConfig: async (config, _) => {
const includes =
config.includes?.map((handle) => {
return {handle}
}) ?? []
const include = config.include ?? []
const inCollection = [...includes, ...include]

// eslint-disable-next-line no-warning-comments
// TODO: Validation to check either one of include or includes was defined

return {
name: config.name,
handle: config.handle,
in_collection: inCollection,
}
oluwatimio marked this conversation as resolved.
Show resolved Hide resolved
},
})

export default editorExtensionCollectionSpecification