@ordergroove/smi-serve 1.9.8 → 1.9.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +0 -1
- package/package.json +2 -2
- package/smi-serve.spec.js +154 -43
- package/src/pull-theme.js +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.9.10](https://github.com/ordergroove/plush-toys/compare/@ordergroove/smi-serve@1.9.9...@ordergroove/smi-serve@1.9.10) (2024-12-11)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @ordergroove/smi-serve
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [1.9.9](https://github.com/ordergroove/plush-toys/compare/@ordergroove/smi-serve@1.9.8...@ordergroove/smi-serve@1.9.9) (2024-11-18)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @ordergroove/smi-serve
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
## [1.9.8](https://github.com/ordergroove/plush-toys/compare/@ordergroove/smi-serve@1.9.7...@ordergroove/smi-serve@1.9.8) (2024-11-15)
|
|
7
23
|
|
|
8
24
|
**Note:** Version bump only for package @ordergroove/smi-serve
|
package/README.md
CHANGED
|
@@ -67,5 +67,4 @@ Ordergroove regularly makes updates to its Subscription Manager templates to fix
|
|
|
67
67
|
## Limitations
|
|
68
68
|
|
|
69
69
|
- Windows is not fully supported, though most functionality should work.
|
|
70
|
-
- smi-serve only reads and writes from your currently published Subscription Manager theme. Draft themes are not currently supported.
|
|
71
70
|
- SSO users and My Organization admins are not currently supported.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ordergroove/smi-serve",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.10",
|
|
4
4
|
"description": "Utility to serve a Subscription Manager template locally",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "Eugenio Lattanzio <eugenio.lattanzio@ordergroove.com>",
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"memfs": "^4.8.2"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "a1708199a5638e704c6c572bae7576115d6a3a2b"
|
|
39
39
|
}
|
package/smi-serve.spec.js
CHANGED
|
@@ -1,66 +1,177 @@
|
|
|
1
|
-
//
|
|
1
|
+
// mock Node fs to be in memory
|
|
2
2
|
jest.mock('fs');
|
|
3
3
|
jest.mock('fs/promises');
|
|
4
4
|
const { vol } = require('memfs');
|
|
5
5
|
|
|
6
|
-
//
|
|
7
|
-
jest.mock('node-fetch', () =>
|
|
8
|
-
|
|
9
|
-
Promise.resolve({
|
|
10
|
-
json: () =>
|
|
11
|
-
Promise.resolve({
|
|
12
|
-
configs: { smi: { files: [{ name: 'views/main.liquid', content: '<h1>Hello</h1>' }] } },
|
|
13
|
-
meta_fields: { dependencies: { '@ordergroove/smi-core': '0.31.6' } }
|
|
14
|
-
})
|
|
15
|
-
})
|
|
16
|
-
)
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
jest.mock('./src/pull-theme', () => ({
|
|
20
|
-
pullTheme: jest.fn().mockResolvedValue()
|
|
21
|
-
}));
|
|
6
|
+
// mock all fetch calls
|
|
7
|
+
jest.mock('node-fetch', () => require('fetch-mock').sandbox());
|
|
8
|
+
jest.mock('inquirer');
|
|
22
9
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
token: 'mock-token',
|
|
26
|
-
merchant: { name: 'test merchant', public_id: 'test-id', ecommerce_platform: 'shopify' }
|
|
27
|
-
})
|
|
28
|
-
}));
|
|
10
|
+
const inquirerMock = require('inquirer');
|
|
11
|
+
const fetchMock = require('node-fetch');
|
|
29
12
|
|
|
13
|
+
// don't run local dev server logic
|
|
14
|
+
jest.mock('./src/serve');
|
|
15
|
+
// mock login function to return a mock token
|
|
16
|
+
jest.mock('./src/login', () => ({
|
|
17
|
+
...jest.requireActual('./src/login'),
|
|
18
|
+
login: jest.fn().mockReturnValue(Promise.resolve('mock-auth'))
|
|
19
|
+
}));
|
|
30
20
|
jest.mock('./src/utils', () => ({
|
|
31
21
|
...jest.requireActual('./src/utils'),
|
|
32
|
-
exec: jest.fn()
|
|
22
|
+
exec: jest.fn() // don't attempt to spawn new processes
|
|
33
23
|
}));
|
|
34
24
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
token: 'mock-token',
|
|
40
|
-
merchant: { name: 'test merchant', public_id: 'test-id' }
|
|
41
|
-
})
|
|
42
|
-
}));
|
|
25
|
+
let promptResponses = [];
|
|
26
|
+
function addMockPromptResponse(message, value) {
|
|
27
|
+
promptResponses.push({ message, value });
|
|
28
|
+
}
|
|
43
29
|
|
|
44
|
-
//
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
30
|
+
// mock out the `inquirer.prompt` function, which takes user input
|
|
31
|
+
inquirerMock.prompt.mockImplementation(([prompt]) => {
|
|
32
|
+
const response = promptResponses.find(response => prompt.message.includes(response.message));
|
|
33
|
+
|
|
34
|
+
if (!response) {
|
|
35
|
+
throw Error(`no mock response defined for prompt: "${prompt.message}"`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (prompt.type === 'autocomplete') {
|
|
39
|
+
// call the `source` function with the mock response value, which filters the list of options
|
|
40
|
+
return Promise.resolve({ [prompt.name]: prompt.source(null, response.value)[0] });
|
|
41
|
+
}
|
|
42
|
+
if (prompt.type === 'list') {
|
|
43
|
+
// get the item in the choices array corresponding to the mock response value
|
|
44
|
+
const selectedOption = prompt.choices.find(choice => choice.name.includes(response.value));
|
|
45
|
+
if (!selectedOption) {
|
|
46
|
+
throw Error(`prompt response value "${response.value}" not found in list of choices`);
|
|
47
|
+
}
|
|
48
|
+
return Promise.resolve({ [prompt.name]: selectedOption.value });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
throw Error(`no mock response defined for prompt type "${prompt.type}"`);
|
|
52
|
+
});
|
|
48
53
|
|
|
49
54
|
const { init } = require('./src/init');
|
|
50
55
|
|
|
51
|
-
|
|
52
|
-
describe('init function', () => {
|
|
56
|
+
describe('smi-serve', () => {
|
|
53
57
|
beforeEach(() => {
|
|
54
|
-
//
|
|
58
|
+
// wipe mock filesystem
|
|
55
59
|
vol.fromJSON({}, '/');
|
|
60
|
+
fetchMock.reset();
|
|
61
|
+
promptResponses = [];
|
|
56
62
|
});
|
|
57
63
|
|
|
58
|
-
it('
|
|
59
|
-
|
|
64
|
+
it('inits with expected files', async () => {
|
|
65
|
+
fetchMock.get('https://rc3.ordergroove.com/api/merchants/', mockSingleMerchantResponse());
|
|
66
|
+
fetchMock.get('https://rc3.ordergroove.com/configs/msi/?merchant_public_id=yum-id', mockMSIConfig());
|
|
67
|
+
fetchMock.get('https://rc3.ordergroove.com/configs/msi/themes/?merchant_public_id=yum-id', mockThemes());
|
|
68
|
+
fetchMock.get('https://static.ordergroove.com/@ordergroove/smi-core/0.31.6/package.json', {
|
|
69
|
+
devDependencies: {
|
|
70
|
+
'@ordergroove/smi-templates': '^0.40.1'
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
fetchMock.get(
|
|
74
|
+
'https://rc3.ordergroove.com/configs/msi/drafts/?merchant_public_id=yum-id&main_theme=main-theme-id',
|
|
75
|
+
mockDraft()
|
|
76
|
+
);
|
|
60
77
|
|
|
61
|
-
|
|
78
|
+
addMockPromptResponse('Select a theme', 'main');
|
|
79
|
+
addMockPromptResponse('Pulling theme will overwrite existing files', 'Overwrite existing theme files');
|
|
80
|
+
|
|
81
|
+
await init({ cwd: '/', configFile: '.ogrc.json', env: 'prod' });
|
|
62
82
|
|
|
63
83
|
const files = vol.toJSON();
|
|
64
|
-
|
|
84
|
+
for (const file of Object.keys(files)) {
|
|
85
|
+
if (file.endsWith('.json')) {
|
|
86
|
+
files[file] = JSON.parse(files[file]);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
expect(files).toEqual({
|
|
90
|
+
'/.gitignore': '.ogrc.json\nnode_modules/\n',
|
|
91
|
+
'/.ogrc.json': {
|
|
92
|
+
prod: {
|
|
93
|
+
token: 'mock-auth',
|
|
94
|
+
merchant: {
|
|
95
|
+
ecommerce_platform: 'shopify',
|
|
96
|
+
name: 'test merchant',
|
|
97
|
+
public_id: 'yum-id',
|
|
98
|
+
selectedTheme: {
|
|
99
|
+
id: 'main-theme-id',
|
|
100
|
+
name: 'main'
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
'/package.json': {
|
|
106
|
+
author: '',
|
|
107
|
+
description: 'Ordergroove Subscription Manager for test merchant on shopify platform (yum-id)}',
|
|
108
|
+
keywords: ['Ordergroove Subscription Manager', 'test merchant', 'yum-id'],
|
|
109
|
+
main: 'views/main.liquid',
|
|
110
|
+
ordergroove: {
|
|
111
|
+
coreVersion: '0.31.6',
|
|
112
|
+
templatesVersion: '0.40.1'
|
|
113
|
+
},
|
|
114
|
+
scripts: {
|
|
115
|
+
start: 'smi-serve'
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
'/styles/main.less': '* { color: red; }',
|
|
119
|
+
'/views/main.liquid': '<h1>Hello world</h1>'
|
|
120
|
+
});
|
|
65
121
|
});
|
|
66
122
|
});
|
|
123
|
+
|
|
124
|
+
function mockSingleMerchantResponse() {
|
|
125
|
+
return [
|
|
126
|
+
{
|
|
127
|
+
name: 'test merchant',
|
|
128
|
+
public_id: 'yum-id',
|
|
129
|
+
ecommerce_platform: 'shopify'
|
|
130
|
+
}
|
|
131
|
+
];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function mockMSIConfig() {
|
|
135
|
+
return {
|
|
136
|
+
...mockDraft(),
|
|
137
|
+
main_theme: 'main-theme-id'
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function mockThemes() {
|
|
142
|
+
return {
|
|
143
|
+
results: [
|
|
144
|
+
{
|
|
145
|
+
id: 'main-theme-id',
|
|
146
|
+
name: 'main'
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function mockDraft() {
|
|
153
|
+
return {
|
|
154
|
+
configs: {
|
|
155
|
+
smi: {
|
|
156
|
+
files: [
|
|
157
|
+
{
|
|
158
|
+
name: '/views/main.liquid',
|
|
159
|
+
content: '<h1>Hello world</h1>'
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: '/styles/main.less',
|
|
163
|
+
content: '* { color: red; }'
|
|
164
|
+
}
|
|
165
|
+
]
|
|
166
|
+
},
|
|
167
|
+
provisioned_with: {
|
|
168
|
+
'@ordergroove/smi-templates': '0.40.1'
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
meta_fields: {
|
|
172
|
+
dependencies: {
|
|
173
|
+
'@ordergroove/smi-core': '0.31.6'
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
package/src/pull-theme.js
CHANGED
|
@@ -16,7 +16,7 @@ async function getThemeList(args) {
|
|
|
16
16
|
|
|
17
17
|
// Fetch theme data for the selected merchant
|
|
18
18
|
const themeResponse = await fetch(
|
|
19
|
-
`${getRC3Url(args)}
|
|
19
|
+
`${getRC3Url(args)}configs/msi/themes/?merchant_public_id=${merchant.public_id}`,
|
|
20
20
|
{
|
|
21
21
|
headers: { Authorization: `Bearer ${token}` }
|
|
22
22
|
}
|
|
@@ -46,7 +46,7 @@ async function getMerchantThemes(args) {
|
|
|
46
46
|
const { token, merchant } = await getValidSettings(args);
|
|
47
47
|
|
|
48
48
|
// Fetch the msi settings which contains main_theme
|
|
49
|
-
const msiSettings = await fetch(`${getRC3Url(args)}
|
|
49
|
+
const msiSettings = await fetch(`${getRC3Url(args)}configs/msi/?merchant_public_id=${merchant.public_id}`, {
|
|
50
50
|
headers: { Authorization: `Bearer ${token}` }
|
|
51
51
|
});
|
|
52
52
|
|
|
@@ -85,7 +85,7 @@ async function fetchThemeFiles(merchantPublicId, themeId, args) {
|
|
|
85
85
|
const { token } = await getValidSettings(args);
|
|
86
86
|
|
|
87
87
|
const themeResponse = await fetch(
|
|
88
|
-
`${getRC3Url(args)}
|
|
88
|
+
`${getRC3Url(args)}configs/msi/drafts/?merchant_public_id=${merchantPublicId}&main_theme=${themeId}`,
|
|
89
89
|
{
|
|
90
90
|
headers: { Authorization: `Bearer ${token}` }
|
|
91
91
|
}
|