Skip to content

Commit c9ad45a

Browse files
vividvioletisaacroldan
authored andcommitted
Support assets for admin links app intents
1 parent bf92dc4 commit c9ad45a

3 files changed

Lines changed: 163 additions & 0 deletions

File tree

packages/app/src/cli/models/extensions/load-specifications.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import webPixelSpec from './specifications/web_pixel_extension.js'
2828
import editorExtensionCollectionSpecification from './specifications/editor_extension_collection.js'
2929
import channelSpecificationSpec from './specifications/channel.js'
3030
import adminSpecificationSpec from './specifications/admin.js'
31+
import adminLinkSpec from './specifications/admin_link.js'
3132

3233
const SORTED_CONFIGURATION_SPEC_IDENTIFIERS = [
3334
BrandingSpecIdentifier,
@@ -80,6 +81,7 @@ function loadSpecifications() {
8081
webPixelSpec,
8182
editorExtensionCollectionSpecification,
8283
channelSpecificationSpec,
84+
adminLinkSpec,
8385
]
8486

8587
return [...configModuleSpecs, ...moduleSpecs] as ExtensionSpecification[]
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import * as loadLocales from '../../../utilities/extensions/locales-configuration.js'
2+
import {ExtensionInstance} from '../extension-instance.js'
3+
import {loadLocalExtensionsSpecifications} from '../load-specifications.js'
4+
import {placeholderAppConfiguration} from '../../app/app.test-data.js'
5+
import {inTemporaryDirectory} from '@shopify/cli-kit/node/fs'
6+
import {joinPath} from '@shopify/cli-kit/node/path'
7+
import {describe, expect, test, vi} from 'vitest'
8+
9+
describe('admin_link', async () => {
10+
async function getTestAdminLink(directory: string, configuration: Record<string, unknown> = {}) {
11+
const configurationPath = joinPath(directory, 'shopify.extension.toml')
12+
const allSpecs = await loadLocalExtensionsSpecifications()
13+
const specification = allSpecs.find((spec) => spec.identifier === 'admin_link')!
14+
const parsed = specification.parseConfigurationObject(configuration)
15+
if (parsed.state !== 'ok') {
16+
throw new Error("Couldn't parse configuration")
17+
}
18+
19+
return new ExtensionInstance({
20+
configuration: parsed.data,
21+
directory,
22+
specification,
23+
configurationPath,
24+
entryPath: '',
25+
})
26+
}
27+
28+
test('has the correct identifier', async () => {
29+
await inTemporaryDirectory(async (tmpDir) => {
30+
const extension = await getTestAdminLink(tmpDir)
31+
expect(extension.specification.identifier).toBe('admin_link')
32+
})
33+
})
34+
35+
test('has localization in appModuleFeatures', async () => {
36+
await inTemporaryDirectory(async (tmpDir) => {
37+
const extension = await getTestAdminLink(tmpDir)
38+
expect(extension.specification.appModuleFeatures()).toContain('localization')
39+
})
40+
})
41+
42+
test('has include_assets client step with generateManifest enabled', async () => {
43+
await inTemporaryDirectory(async (tmpDir) => {
44+
const extension = await getTestAdminLink(tmpDir)
45+
const clientSteps = extension.specification.clientSteps!
46+
expect(clientSteps).toHaveLength(1)
47+
expect(clientSteps[0]!.lifecycle).toBe('deploy')
48+
49+
const steps = clientSteps[0]!.steps
50+
expect(steps).toHaveLength(1)
51+
expect(steps[0]).toMatchObject({
52+
id: 'copy-admin-link-assets',
53+
name: 'Copy Admin Link Assets',
54+
type: 'include_assets',
55+
config: {
56+
generateManifest: true,
57+
inclusions: [
58+
{type: 'configKey', key: 'targeting[].tools'},
59+
{type: 'configKey', key: 'targeting[].instructions'},
60+
{type: 'configKey', key: 'targeting[].intents[].schema'},
61+
],
62+
},
63+
})
64+
})
65+
})
66+
67+
describe('deployConfig()', () => {
68+
test('includes localization in deploy config', async () => {
69+
await inTemporaryDirectory(async (tmpDir) => {
70+
const localization = {
71+
default_locale: 'en',
72+
translations: {title: 'Hello!'},
73+
}
74+
vi.spyOn(loadLocales, 'loadLocalesConfig').mockResolvedValue(localization)
75+
76+
const extension = await getTestAdminLink(tmpDir, {
77+
name: 'My Admin Link',
78+
targeting: [{url: 'https://example.com'}],
79+
})
80+
81+
const deployConfig = await extension.deployConfig({
82+
apiKey: 'apiKey',
83+
appConfiguration: placeholderAppConfiguration,
84+
})
85+
86+
expect(deployConfig).toMatchObject({localization})
87+
expect(loadLocales.loadLocalesConfig).toHaveBeenCalledWith(tmpDir, 'admin_link')
88+
})
89+
})
90+
91+
test('strips first-class fields from deploy config', async () => {
92+
await inTemporaryDirectory(async (tmpDir) => {
93+
vi.spyOn(loadLocales, 'loadLocalesConfig').mockResolvedValue({})
94+
95+
const extension = await getTestAdminLink(tmpDir, {
96+
type: 'admin_link',
97+
handle: 'my-link',
98+
name: 'My Admin Link',
99+
targeting: [{url: 'https://example.com'}],
100+
})
101+
102+
const deployConfig = await extension.deployConfig({
103+
apiKey: 'apiKey',
104+
appConfiguration: placeholderAppConfiguration,
105+
})
106+
107+
expect(deployConfig).not.toHaveProperty('type')
108+
expect(deployConfig).not.toHaveProperty('handle')
109+
expect(deployConfig).toHaveProperty('name', 'My Admin Link')
110+
expect(deployConfig).toHaveProperty('targeting')
111+
})
112+
})
113+
})
114+
})
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import {createContractBasedModuleSpecification} from '../specification.js'
2+
3+
const adminLinkSpec = createContractBasedModuleSpecification({
4+
identifier: 'admin_link',
5+
buildConfig: {
6+
mode: 'copy_files',
7+
filePatterns: [],
8+
},
9+
clientSteps: [
10+
{
11+
lifecycle: 'deploy',
12+
steps: [
13+
{
14+
id: 'include-admin-link-assets',
15+
name: 'Include Admin Link Assets',
16+
type: 'include_assets',
17+
config: {
18+
generatesAssetsManifest: true,
19+
inclusions: [
20+
{
21+
type: 'configKey',
22+
anchor: 'extensions[].targeting[]',
23+
groupBy: 'target',
24+
key: 'tools',
25+
},
26+
{
27+
type: 'configKey',
28+
anchor: 'extensions[].targeting[]',
29+
groupBy: 'target',
30+
key: 'instructions',
31+
},
32+
{
33+
type: 'configKey',
34+
anchor: 'extensions[].targeting[]',
35+
groupBy: 'target',
36+
key: 'intents[].schema',
37+
},
38+
],
39+
},
40+
},
41+
],
42+
},
43+
],
44+
appModuleFeatures: () => ['localization'],
45+
})
46+
47+
export default adminLinkSpec

0 commit comments

Comments
 (0)