Skip to content
This repository has been archived by the owner on Nov 4, 2024. It is now read-only.

Commit

Permalink
fix: exit successfully when submitting a listed add-on (#91)
Browse files Browse the repository at this point in the history
* chore: add allowed channels constants

* chore: tests

* test: wip

* test: wip use union fs

* test: wip use memfs

* test: wip

* chore: use memfs

* test: move mock to setup

* chore: ensure caveat only applies for listed and autosign

* chore: only check if folder exists
  • Loading branch information
iamogbz authored Mar 17, 2020
1 parent 0ae3053 commit da4a362
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 88 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@tophat/commitizen-adapter": "^0.0.11",
"@tophat/commitlint-config": "^0.1.2",
"@tophat/eslint-config": "^0.6.0",
"@types/jest": "^25.1.4",
"aggregate-error": "^3.0.1",
"all-contributors-cli": "^6.9.1",
"babel-eslint": "^10.0.2",
Expand All @@ -38,14 +39,15 @@
"memfs": "^3.0.3",
"prettier": "^1.18.2",
"semantic-release": "^17.0.1",
"unionfs": "^4.4.0",
"yarn-deduplicate": "^2.0.0"
},
"scripts": {
"build": "mkdir -p artifacts; echo 'When changing this remember to update @semantic-release/npm.'",
"commit": "git-cz",
"lock-check": "yarn-deduplicate --list --fail",
"lock-dedup": "yarn-deduplicate",
"lint": "eslint . --ext .js,.ts --max-warnings=0",
"postinstall": "yarn-deduplicate",
"release": "semantic-release",
"report-coverage": "codecov",
"test": "jest",
Expand Down
8 changes: 7 additions & 1 deletion src/constants.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
const allowedChannels = {
LISTED: 'listed',
UNLISTED: 'unlisted',
}

const defaultOptions = {
artifactsDir: './artifacts',
channel: 'unlisted',
channel: allowedChannels.UNLISTED,
manifestPath: 'manifest.json',
sourceDir: 'dist',
}
Expand All @@ -18,6 +23,7 @@ const requiredEnvs = {
}

module.exports = {
allowedChannels,
defaultOptions,
requiredEnvs,
requiredOptions,
Expand Down
25 changes: 14 additions & 11 deletions src/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const path = require('path')
const webExt = require('web-ext').default
const defaultAddonSigner = require('sign-addon')

const { allowedChannels } = require('./constants')
const { verifyOptions } = require('./utils')

const publish = async options => {
Expand All @@ -24,18 +25,25 @@ const publish = async options => {

const { FIREFOX_API_KEY, FIREFOX_SECRET_KEY } = process.env

let unsignedXpiPath
const signAddon = async params => {
unsignedXpiPath = params.xpiPath
const unsignedXpiFile = `unsigned-${targetXpi}`
fs.writeFileSync(
path.join(artifactsDir, unsignedXpiFile),
fs.readFileSync(params.xpiPath),
)
const result = await defaultAddonSigner(params)
if (!result.success && result.errorCode === 'ADDON_NOT_AUTO_SIGNED') {
if (
channel === allowedChannels.LISTED &&
!result.success &&
result.errorCode === 'ADDON_NOT_AUTO_SIGNED'
) {
result.success = true
result.downloadedFiles = result.downloadedFiles || []
result.downloadedFiles = result.downloadedFiles || [unsignedXpiFile]
}
return result
}

const { success, downloadedFiles } = await webExt.cmd.sign(
const { downloadedFiles } = await webExt.cmd.sign(
{
apiKey: FIREFOX_API_KEY,
apiSecret: FIREFOX_SECRET_KEY,
Expand All @@ -46,14 +54,9 @@ const publish = async options => {
},
{ signAddon },
)
if (!success) {
throw new Error(
'Signing the extension failed. See the console output from web-ext sign for the validation link',
)
}
const [xpiFile] = downloadedFiles
fs.renameSync(
xpiFile ? path.join(artifactsDir, xpiFile) : unsignedXpiPath,
path.join(artifactsDir, xpiFile),
path.join(artifactsDir, targetXpi),
)
}
Expand Down
21 changes: 19 additions & 2 deletions tests/__mocks__/fs.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
const { fs } = require('memfs')
const path = jest.requireActual('path')
const fs = jest.requireActual('fs')
const { vol } = require('memfs')
const { ufs } = require('unionfs')

module.exports = fs
const { createWriteStream } = ufs
ufs.createWriteStream = (...args) => {
for (const _fs of ufs.fss) {
try {
if (_fs.existsSync(path.dirname(`${args[0]}`))) {
return _fs.createWriteStream(args[0])
}
} catch (e) {
continue
}
}
return createWriteStream(...args)
}

module.exports = ufs.use(vol).use(fs)
1 change: 1 addition & 0 deletions tests/__mocks__/sign-addon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = jest.fn()
6 changes: 0 additions & 6 deletions tests/__mocks__/web-ext.js

This file was deleted.

4 changes: 3 additions & 1 deletion tests/prepare.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
const { fs, vol } = require('memfs')
const fs = require('fs')

const { vol } = require('memfs')

const { prepare } = require('../src')

Expand Down
72 changes: 61 additions & 11 deletions tests/publish.test.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,49 @@
const { fs, vol } = require('memfs')
const { default: webExt } = require('web-ext')
const fs = require('fs')
const path = require('path')

const { vol } = require('memfs')
const signAddon = require('sign-addon')

const { publish } = require('../src')

describe('publish', () => {
const mockManifestJSON = {
manifest_version: 2,
name: 'Mock Extension',
version: '0.0.1',
}
const extensionId = '{01234567-abcd-6789-cdef-0123456789ef}'
const targetXpi = 'target-extension.xpi'
const mockOptions = {
artifactsDir: 'mock_artifacts',
manifestPath: 'mock_manifest.json',
channel: 'unlisted',
manifestPath: 'manifest.json',
sourceDir: 'mock_source',
}
const completeOptions = { extensionId, targetXpi, ...mockOptions }
const mockAddonSignFailed = { success: false }
const mockAddonSignSuccess = { success: true, id: extensionId }
const clearMockArtifacts = () => {
const actualFs = jest.requireActual('fs')
if (actualFs.existsSync(mockOptions.artifactsDir)) {
actualFs.rmdirSync(mockOptions.artifactsDir, { recursive: true })
}
}

beforeAll(() => {
jest.spyOn(console, 'log')
})
beforeEach(() => {
vol.fromJSON({
[path.join(
mockOptions.sourceDir,
mockOptions.manifestPath,
)]: JSON.stringify(mockManifestJSON),
})
})
afterEach(() => {
vol.reset()
clearMockArtifacts()
jest.clearAllMocks()
})
afterAll(() => {
Expand All @@ -36,25 +62,49 @@ describe('publish', () => {
)
})

it('raises error if signing unsuccessful', () => {
webExt.cmd.sign.mockResolvedValueOnce({ success: false })
it.each`
signCase | signResults
${'signing unsuccessful'} | ${mockAddonSignFailed}
${'auto signing unsuccessful and channel is unlisted'} | ${{ ...mockAddonSignFailed, errorCode: 'ADDON_NOT_AUTO_SIGNED' }}
`('raises error if $signCase', ({ signResults }) => {
signAddon.mockResolvedValueOnce(signResults)
return expect(publish(completeOptions)).rejects.toThrow(
'Signing the extension failed',
'The extension could not be signed',
)
})

it('uses unsigned xpi if auto signing unsuccessful and channel is listed', async () => {
signAddon.mockResolvedValueOnce({
...mockAddonSignFailed,
errorCode: 'ADDON_NOT_AUTO_SIGNED',
})
const targetXpiPath = path.join(mockOptions.artifactsDir, targetXpi)
expect(fs.existsSync(targetXpiPath)).toBe(false)
await publish({
...completeOptions,
channel: 'listed',
})
expect(fs.existsSync(targetXpiPath)).toBe(true)
})

it('renames downloaded file to target xpi', async () => {
const downloadedFile = 'mock_downloaded.xpi'
const mockFileContent = 'some fake signed xpi'
vol.fromJSON({
[`${mockOptions.artifactsDir}/${downloadedFile}`]: 'some fake signed xpi',
[path.join(
mockOptions.artifactsDir,
downloadedFile,
)]: mockFileContent,
})
webExt.cmd.sign.mockResolvedValueOnce({
success: true,
signAddon.mockResolvedValueOnce({
...mockAddonSignSuccess,
downloadedFiles: [downloadedFile],
})
const targetXpiPath = `${mockOptions.artifactsDir}/${targetXpi}`
const targetXpiPath = path.join(mockOptions.artifactsDir, targetXpi)
expect(fs.existsSync(targetXpiPath)).toBe(false)
await publish(completeOptions)
expect(fs.existsSync(targetXpiPath)).toBe(true)
expect(fs.readFileSync(targetXpiPath).toString()).toEqual(
mockFileContent,
)
})
})
2 changes: 1 addition & 1 deletion tests/setup.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
jest.mock('fs')
jest.mock('web-ext')
jest.mock('sign-addon')
Loading

0 comments on commit da4a362

Please sign in to comment.