1 | const fs = require('fs');
|
2 | const path = require('path');
|
3 | const glob = require('glob');
|
4 | const dotenv = require('dotenv');
|
5 | const SlateConfig = require('@shopify/slate-config');
|
6 |
|
7 | const slateEnv = require('../index');
|
8 | const config = new SlateConfig(require('../slate-env.schema'));
|
9 |
|
10 | const envPath = path.resolve(
|
11 | config.get('env.rootDirectory'),
|
12 | config.get('env.basename'),
|
13 | );
|
14 |
|
15 | const TEST_ENV = {
|
16 | [config.get('env.keys.name')]: 'production',
|
17 | [config.get('env.keys.store')]: 'test-shop.myshopify.com',
|
18 | [config.get('env.keys.password')]: '123456789',
|
19 | [config.get('env.keys.themeId')]: '987654321',
|
20 | [config.get('env.keys.ignoreFiles')]: 'config/settings_data.json',
|
21 | [config.get('env.keys.userEmail')]: 'test@email.com',
|
22 | };
|
23 |
|
24 | function setVars(vars) {
|
25 | for (const key in vars) {
|
26 | if (vars.hasOwnProperty(key)) {
|
27 | process.env[key] = vars[key];
|
28 | }
|
29 | }
|
30 | }
|
31 |
|
32 | function clearVars(vars) {
|
33 | for (const key in vars) {
|
34 | if (vars.hasOwnProperty(key)) {
|
35 | delete process.env[key];
|
36 | }
|
37 | }
|
38 | }
|
39 |
|
40 | afterEach(() => {
|
41 | clearVars(TEST_ENV);
|
42 | glob.sync(`${envPath}*`).forEach((file) => fs.unlinkSync(file));
|
43 | });
|
44 |
|
45 | describe('Slate Env', () => {
|
46 | describe('clear()', () => {
|
47 | beforeEach(() => {
|
48 | setVars(TEST_ENV);
|
49 | });
|
50 |
|
51 | test('Clears all the values assigned to Slate environment variables', () => {
|
52 | slateEnv.clear();
|
53 |
|
54 | for (const key in TEST_ENV) {
|
55 | if (TEST_ENV.hasOwnProperty(key)) {
|
56 | expect(process.env[key]).toBe('');
|
57 | }
|
58 | }
|
59 | });
|
60 | });
|
61 |
|
62 | describe('getSlateEnv()', () => {
|
63 | beforeEach(() => {
|
64 | setVars(TEST_ENV);
|
65 | });
|
66 |
|
67 | test('returns object containing all env variables without current values', () => {
|
68 | expect(slateEnv.getSlateEnv()).toEqual(TEST_ENV);
|
69 | });
|
70 | });
|
71 |
|
72 | describe('getDefaultSlateEnv', () => {
|
73 | test('returns an object which contains the default variables and values of an env file', () => {
|
74 | const emptyTestVars = {
|
75 | [config.get('env.keys.store')]: '',
|
76 | [config.get('env.keys.password')]: '',
|
77 | [config.get('env.keys.themeId')]: '',
|
78 | [config.get('env.keys.ignoreFiles')]: '',
|
79 | };
|
80 |
|
81 | expect(slateEnv.getDefaultSlateEnv()).toEqual(emptyTestVars);
|
82 | });
|
83 | });
|
84 |
|
85 | describe('getEmptySlateEnv()', () => {
|
86 | test('returns object containing all env file variables with empty values', () => {
|
87 | const emptyTestVars = Object.assign({}, TEST_ENV);
|
88 |
|
89 | for (const key in emptyTestVars) {
|
90 | if (emptyTestVars.hasOwnProperty(key)) {
|
91 | emptyTestVars[key] = '';
|
92 | }
|
93 | }
|
94 |
|
95 | expect(slateEnv.getEmptySlateEnv()).toEqual(emptyTestVars);
|
96 | });
|
97 | });
|
98 |
|
99 | describe('create()', () => {
|
100 | describe('generates an .env file', () => {
|
101 | test('with empty config values', () => {
|
102 | slateEnv.create();
|
103 |
|
104 | const envParsed = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
105 |
|
106 | expect(envParsed).toEqual({
|
107 | [config.get('env.keys.store')]: '',
|
108 | [config.get('env.keys.password')]: '',
|
109 | [config.get('env.keys.themeId')]: '',
|
110 | [config.get('env.keys.ignoreFiles')]: '',
|
111 | });
|
112 | });
|
113 |
|
114 | test('with specified config values', () => {
|
115 | const env = slateEnv.getEmptySlateEnv();
|
116 | const store = 'test-shop.myshopify.com';
|
117 |
|
118 | env[config.get('env.keys.store')] = store;
|
119 | slateEnv.create({values: env});
|
120 |
|
121 | const envParsed = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
122 |
|
123 | expect(envParsed).toHaveProperty(config.get('env.keys.store'), store);
|
124 | });
|
125 |
|
126 | test('with invalid config values ommited', () => {
|
127 | const env = slateEnv.getEmptySlateEnv();
|
128 | const store = 'test-shop.myshopify.com';
|
129 | const invalidKey = 'INVALID_VARIABLE';
|
130 | const invalidValue = 'some value';
|
131 |
|
132 | env[config.get('env.keys.store')] = store;
|
133 | env[invalidKey] = invalidValue;
|
134 | slateEnv.create({values: env});
|
135 |
|
136 | const envParsed = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
137 |
|
138 | expect(envParsed).toHaveProperty(config.get('env.keys.store'), store);
|
139 | expect(envParsed).not.toHaveProperty(invalidKey, invalidValue);
|
140 | });
|
141 |
|
142 | test('when a valid name is provided', () => {
|
143 | const name = 'production';
|
144 | const namedEnvPath = envPath.concat(`.${name}`);
|
145 |
|
146 | slateEnv.create({name});
|
147 | expect(fs.existsSync(namedEnvPath)).toBeTruthy();
|
148 | });
|
149 |
|
150 | test('when no name is provided', () => {
|
151 | slateEnv.create();
|
152 | expect(fs.existsSync(envPath)).toBeTruthy();
|
153 | });
|
154 |
|
155 | test('when an empty name ("") is provided', () => {
|
156 | slateEnv.create({}, '');
|
157 | expect(fs.existsSync(envPath)).toBeTruthy();
|
158 | });
|
159 |
|
160 | test('when a whitespace name (" ") is provided', () => {
|
161 | slateEnv.create({}, ' ');
|
162 | expect(fs.existsSync(envPath)).toBeTruthy();
|
163 | });
|
164 | });
|
165 | });
|
166 |
|
167 | describe('assign()', () => {
|
168 | beforeEach(() => {
|
169 | slateEnv.create({values: TEST_ENV});
|
170 | slateEnv.create({values: TEST_ENV, name: 'production'});
|
171 | });
|
172 |
|
173 | test('reads default env file and assigns values to environment variables', () => {
|
174 | slateEnv.assign();
|
175 | expect(process.env[config.get('env.keys.store')]).toBe(
|
176 | TEST_ENV[config.get('env.keys.store')],
|
177 | );
|
178 | });
|
179 |
|
180 | test('reads named env file and assigns values to environment variables', () => {
|
181 | slateEnv.assign('production');
|
182 | expect(process.env[config.get('env.keys.store')]).toBe(
|
183 | TEST_ENV[config.get('env.keys.store')],
|
184 | );
|
185 | });
|
186 |
|
187 | test('does not overwrite an environment variable if it already has a value', () => {
|
188 | const store = 'other-value.myshopify.com';
|
189 | process.env[config.get('env.keys.store')] = store;
|
190 | slateEnv.assign();
|
191 |
|
192 | expect(process.env[config.get('env.keys.store')]).toBe(store);
|
193 | });
|
194 |
|
195 | test("throw an error if a name is provided and the env file doesn't exist", () => {
|
196 | expect(() => slateEnv.assign('nope')).toThrow();
|
197 | });
|
198 | });
|
199 |
|
200 | describe('getEnvName()', () => {
|
201 | describe('if a env name is specified', () => {
|
202 | beforeEach(() => {
|
203 | slateEnv.create({values: TEST_ENV, name: 'production'});
|
204 | slateEnv.assign('production');
|
205 | });
|
206 |
|
207 | test('returns the name of the environment', () => {
|
208 | expect(slateEnv.getEnvNameValue()).toBe('production');
|
209 | });
|
210 | });
|
211 |
|
212 | describe('if a env name is not specified', () => {
|
213 | test(`returns the name '${config.get(
|
214 | 'env.defaultEnvName',
|
215 | )}' if the default env file is present`, () => {
|
216 | slateEnv.create(TEST_ENV);
|
217 | slateEnv.assign();
|
218 | expect(slateEnv.getEnvNameValue()).toBe(
|
219 | config.get('env.defaultEnvName'),
|
220 | );
|
221 | });
|
222 | test(`returns the name '${config.get(
|
223 | 'env.externalEnvName',
|
224 | )}' if the default env file is not present`, () => {
|
225 | slateEnv.assign();
|
226 | expect(slateEnv.getEnvNameValue()).toBe(
|
227 | config.get('env.externalEnvName'),
|
228 | );
|
229 | });
|
230 | });
|
231 | });
|
232 |
|
233 | describe('getStoreValue()', () => {
|
234 | test('returns the value of the environment variable that references the store URL', () => {
|
235 | process.env[config.get('env.keys.store')] =
|
236 | TEST_ENV[config.get('env.keys.store')];
|
237 | expect(slateEnv.getStoreValue()).toBe(
|
238 | TEST_ENV[config.get('env.keys.store')],
|
239 | );
|
240 | });
|
241 |
|
242 | test('returns an empty string if the value is undefined', () => {
|
243 | expect(slateEnv.getStoreValue()).toBe('');
|
244 | });
|
245 | });
|
246 |
|
247 | describe('getPasswordValue()', () => {
|
248 | test('returns the value of the environment variable that references the store API password', () => {
|
249 | process.env[config.get('env.keys.password')] =
|
250 | TEST_ENV[config.get('env.keys.password')];
|
251 | expect(slateEnv.getPasswordValue()).toBe(
|
252 | TEST_ENV[config.get('env.keys.password')],
|
253 | );
|
254 | });
|
255 |
|
256 | test('returns an empty string if the value is undefined', () => {
|
257 | expect(slateEnv.getPasswordValue()).toBe('');
|
258 | });
|
259 | });
|
260 |
|
261 | describe('getThemeIdValue()', () => {
|
262 | test('returns the value of the environment variable that references the store theme ID', () => {
|
263 | process.env[config.get('env.keys.themeId')] =
|
264 | TEST_ENV[config.get('env.keys.themeId')];
|
265 | expect(slateEnv.getThemeIdValue()).toBe(
|
266 | TEST_ENV[config.get('env.keys.themeId')],
|
267 | );
|
268 | });
|
269 |
|
270 | test('returns an empty string if the value is undefined', () => {
|
271 | expect(slateEnv.getThemeIdValue()).toBe('');
|
272 | });
|
273 | });
|
274 |
|
275 | describe('getIgnoreFilesValue()', () => {
|
276 | test('returns the value of the environment variable that references a list of files to ignore', () => {
|
277 | process.env[config.get('env.keys.ignoreFiles')] =
|
278 | TEST_ENV[config.get('env.keys.ignoreFiles')];
|
279 | expect(slateEnv.getIgnoreFilesValue()).toBe(
|
280 | TEST_ENV[config.get('env.keys.ignoreFiles')],
|
281 | );
|
282 | });
|
283 |
|
284 | test('returns an empty string if the value is undefined', () => {
|
285 | expect(slateEnv.getIgnoreFilesValue()).toBe('');
|
286 | });
|
287 | });
|
288 |
|
289 | describe('validate()', () => {
|
290 | describe('returns an object with an .isValid prop', () => {
|
291 | test('that is true if no validation .errors is empty', () => {
|
292 | setVars(TEST_ENV);
|
293 | const result = slateEnv.validate();
|
294 | expect(result).toHaveProperty('isValid', true);
|
295 | expect(result.errors).toBeDefined();
|
296 | expect(result.errors).toHaveLength(0);
|
297 | });
|
298 |
|
299 | test('that is false validation .errors is not empty', () => {
|
300 | const result = slateEnv.validate();
|
301 | expect(result).toHaveProperty('isValid', false);
|
302 | expect(result.errors).toBeDefined();
|
303 | expect(result.errors.length).toBeGreaterThan(0);
|
304 | });
|
305 | });
|
306 | describe('returns errors if', () => {
|
307 | test('the store URL environment variable is empty', () => {
|
308 | setVars(
|
309 | Object.assign({}, TEST_ENV, {
|
310 | [config.get('env.keys.store')]: '',
|
311 | }),
|
312 | );
|
313 | const result = slateEnv.validate();
|
314 | expect(result.errors).toHaveLength(1);
|
315 | });
|
316 |
|
317 | test('the store URL environment variable is not a .myshopify.com or myshopify.io URL', () => {
|
318 | ['shop1.myshopify.com', 'shop1.myshopify.io', 'shop1'].forEach(
|
319 | (value) => {
|
320 | setVars(
|
321 | Object.assign({}, TEST_ENV, {
|
322 | [config.get('env.keys.store')]: value,
|
323 | }),
|
324 | );
|
325 | const result = slateEnv.validate();
|
326 | expect(result.errors).toHaveLength(value === 'shop1' ? 1 : 0);
|
327 | },
|
328 | );
|
329 | });
|
330 |
|
331 | test('the store URL environment variable does not end with a trailing slash', () => {
|
332 | ['shop1.myshopify.com', 'shop1.myshopify.com/'].forEach((value) => {
|
333 | setVars(
|
334 | Object.assign({}, TEST_ENV, {
|
335 | [config.get('env.keys.store')]: value,
|
336 | }),
|
337 | );
|
338 | const result = slateEnv.validate();
|
339 | expect(result.errors).toHaveLength(
|
340 | value === 'shop1.myshopify.com/' ? 1 : 0,
|
341 | );
|
342 | });
|
343 | });
|
344 |
|
345 | test('the store API password environment variable is empty', () => {
|
346 | setVars(
|
347 | Object.assign({}, TEST_ENV, {
|
348 | [config.get('env.keys.password')]: '',
|
349 | }),
|
350 | );
|
351 | const result = slateEnv.validate();
|
352 | expect(result.errors).toHaveLength(1);
|
353 | });
|
354 |
|
355 | test('the store API password environment variable has invalid characters', () => {
|
356 | setVars(
|
357 | Object.assign({}, TEST_ENV, {
|
358 | [config.get('env.keys.password')]: '8h1j-dnjn8',
|
359 | }),
|
360 | );
|
361 | const result = slateEnv.validate();
|
362 | expect(result.errors).toHaveLength(1);
|
363 | });
|
364 |
|
365 | test('the store Theme ID environment variable is empty', () => {
|
366 | setVars(
|
367 | Object.assign({}, TEST_ENV, {
|
368 | [config.get('env.keys.themeId')]: '',
|
369 | }),
|
370 | );
|
371 | const result = slateEnv.validate();
|
372 | expect(result.errors).toHaveLength(1);
|
373 | });
|
374 |
|
375 | test("the store Theme ID environment variable is not 'live' or a string of numbers", () => {
|
376 | setVars(
|
377 | Object.assign({}, TEST_ENV, {
|
378 | [config.get('env.keys.themeId')]: 'ds7dsh8d',
|
379 | }),
|
380 | );
|
381 | const result = slateEnv.validate();
|
382 | expect(result.errors).toHaveLength(1);
|
383 | });
|
384 | });
|
385 | });
|
386 | });
|