@adobe/aio-lib-web
Version:
Utility tooling library to build and deploy Adobe I/O Project Firefly app static sites to CDN
219 lines (195 loc) • 6.46 kB
JavaScript
/*
Copyright 2019 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/
const cloneDeep = require('lodash.clonedeep')
const path = require('path')
jest.setTimeout(10000)
process.on('unhandledRejection', error => {
throw error
})
const fixturePath = path.join(__dirname, '__fixtures__')
// quick normalization to test windows paths
global.n = p => path.normalize(p)
global.r = p => path.resolve(p)
/**
* reads a dir or a file to a json
* if filePath is a dir at /a/b/c/ and contains d/e.txt f/g/h.txt and toDir is /adir/ will return a json:
* ```
* {
* "/adir/d/e.txt": "<content>",
* "/adir/f/g/h.txt": "<content>"
* }
* ```
*
* @param {string} filePath
* @param {string} toDir
* @returns {object}
*/
function readFilesIntoObjectSync (filePath, toDir) {
const fsReal = jest.requireActual('fs')
const flatObj = {}
function _readFilesIntoObjectSync (_filePathRec, _toDirRec, first = false) {
const stat = fsReal.statSync(_filePathRec)
if (!stat.isFile() && !stat.isDirectory()) {
throw new Error(_filePathRec + ' is not a valid file, cannot be addded to mockfs')
}
if (stat.isFile()) {
flatObj[path.join(_toDirRec, path.basename(_filePathRec))] = fsReal.readFileSync(_filePathRec).toString()
return
}
// is dir
const files = fsReal.readdirSync(_filePathRec)
files.forEach(f => {
const fullPath = path.join(_filePathRec, f)
// skip first dir from path
_readFilesIntoObjectSync(fullPath, first ? _toDirRec : path.join(_toDirRec, path.basename(_filePathRec)))
})
}
_readFilesIntoObjectSync(filePath, toDir, true)
return flatObj
}
global.mockFs = () => {
const memfs = require('memfs')
const vol = memfs.vol
const mockFs = memfs.fs
jest.mock('fs', () => mockFs)
return { vol, fs: mockFs }
}
global.loadFs = (vol, fixtures) => {
if (typeof fixtures === 'string') fixtures = [fixtures]
const jsonFs = fixtures
.map(f => readFilesIntoObjectSync(path.join(fixturePath, f), '/')) // => [{}, {}, ..]
.reduce((aggregate, currObj) => ({ ...aggregate, ...currObj }), {}) // => {}
// For now we can only store files on / as chdir does not recognize mock fs files and we rely on cwd to set the root
// path of the project
// todo have an option to pass rootDir as arg instead of cwd
vol.fromJSON(jsonFs, '/', { reset: true })
process.chdir('/')
}
global.cleanFs = vol => vol.reset()
global.addFakeFiles = (vol, dir, files) => {
if (typeof files === 'string') files = [files]
if (Array.isArray(files)) files = files.reduce((obj, curr) => { obj[curr] = 'fake-content'; return obj }, {})
vol.mkdirpSync(dir)
Object.keys(files).forEach(f => {
const filePath = path.join(dir, f)
// create intermediate directories if neccessary
vol.mkdirSync(path.dirname(filePath), { recursive: true })
vol.writeFileSync(filePath, files[f])
})
}
global.configWithMissing = (config, members) => {
if (typeof members === 'string') members = [members]
config = cloneDeep(config)
members.forEach(m => {
// a config member can be hierarchical e.g. 'my.config.that.i.want.to.remove'
const split = m.split('.')
const last = split.pop()
const traverse = split.reduce((_traverse, next) => _traverse[next], config)
delete traverse[last]
})
return config
}
global.configWithModifiedWeb = (config, newWebConfig) => {
config = cloneDeep(config)
config.web = newWebConfig
return config
}
global.fakeS3Bucket = 'fake-bucket'
global.fakeConfig = {
tvm: {
runtime: {
namespace: 'fake_ns',
auth: 'fake:auth'
}
},
local: {
runtime: {
// those must match the once set by dev cmd
apihost: 'http://localhost:3233',
namespace: 'guest',
auth: '23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP'
}
},
creds: {
runtime: {
namespace: 'fake_ns',
auth: 'fake:auth'
},
cna: {
s3bucket: 'customBucket',
awsaccesskeyid: 'fakeAwsKeyId',
awssecretaccesskey: 'fakeAwsSecretKey'
}
},
app: {
htmlCacheDuration: 60,
jsCacheDuration: 604800,
cssCacheDuration: 604800,
imageCacheDuration: 604800
},
web: {
'response-headers': {
'/*': {
testHeader: 'foo'
}
}
}
}
global.fakeTVMResponse = {
sessionToken: 'fake',
expiration: '1970-01-01T00:00:00.000Z',
accessKeyId: 'fake',
secretAccessKey: 'fake',
params: { Bucket: global.fakeS3Bucket }
}
global.fakeBYOCredentials = {
accessKeyId: 'fake',
secretAccessKey: 'fake',
params: { Bucket: global.fakeS3Bucket }
}
global.expectedScripts = expect.objectContaining({
buildUI: expect.any(Function),
deployUI: expect.any(Function),
undeployUI: expect.any(Function)
})
global.expectedS3ENVCreds = expect.objectContaining({
accessKeyId: expect.any(String),
secretAccessKey: expect.any(String),
params: { Bucket: expect.any(String) }
})
global.expectedS3TVMCreds = expect.objectContaining({
sessionToken: expect.any(String),
expiration: expect.any(String),
accessKeyId: expect.any(String),
secretAccessKey: expect.any(String),
params: { Bucket: expect.any(String) }
})
global.defaultAppHostName = 'adobeio-static.net'
global.defaultTvmUrl = 'https://adobeio.adobeioruntime.net/apis/tvm/'
global.defaultOwApiHost = 'https://adobeioruntime.net'
expect.extend({
async toThrowWithMessageContaining (received, args) {
try {
await received()
} catch (e) {
if (typeof args === 'string') args = [args]
const message = e.message.toLowerCase()
for (let i = 0; i < args.length; ++i) {
const a = args[i].toLowerCase()
if (message.indexOf(a) < 0) {
return { message: () => `expected "${message}" to contain "${a}"`, pass: false }
}
}
return { pass: true }
}
return { message: () => 'function should have thrown', pass: false }
}
})