Skip to content

Commit cbfde67

Browse files
Only determine that a plugin is installed if the package.json for the plugin exists where it is expected.
1 parent 69b8887 commit cbfde67

8 files changed

Lines changed: 76 additions & 18 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Fixes
66

7+
- [#2251: Fix plugin page failure after updating to 13.10.0](https://github.com/alphagov/govuk-prototype-kit/pull/2251)
8+
79
- [#2253: Add comments to the prototype-starter filters file](https://github.com/alphagov/govuk-prototype-kit/pull/2253)
810

911
## 13.10.0

cypress/e2e/plugins/0-mock-plugin-tests/install-plugin-via-ui-test.cypress.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const panelCompleteQuery = '[aria-live="polite"] #panel-complete'
66
const fixtures = path.join(Cypress.config('fixturesFolder'))
77
const dependentPlugin = 'plugin-fee'
88
const dependentPluginName = 'Plugin Fee'
9-
const dependentPluginLocation = path.join(fixtures, 'plugins', dependentPlugin)
9+
const dependentPluginLocation = [fixtures, 'plugins', dependentPlugin].join(Cypress.config('pathSeparator'))
1010
const dependencyPlugin = 'govuk-frontend'
1111
const dependencyPluginName = 'GOV.UK Frontend'
1212

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const { replaceInFile, waitForApplication, uninstallPlugin, log } = require('../../utils')
2+
const path = require('path')
3+
const plugin = '@govuk-prototype-kit/task-list'
4+
const pluginVersion = '1.1.1'
5+
const originalText = '"dependencies": {'
6+
const replacementText = `"dependencies": { "${plugin}": "${pluginVersion}",`
7+
const pkgJsonFile = path.join(Cypress.env('projectFolder'), 'package.json')
8+
const pluginsPage = '/manage-prototype/plugins'
9+
10+
function restore () {
11+
uninstallPlugin(plugin)
12+
}
13+
14+
describe('Handle a plugin installation mismatch', () => {
15+
before(restore)
16+
after(restore)
17+
18+
it('where the prototype package.json specifies a dependency that has not been installed', () => {
19+
waitForApplication()
20+
21+
log(`Add ${plugin} to the dependencies within the package.json`)
22+
replaceInFile(pkgJsonFile, originalText, '', replacementText)
23+
24+
log(`Make sure ${plugin} is displayed as not installed`)
25+
cy.visit(pluginsPage)
26+
cy.get(`[data-plugin-package-name="${plugin}"]`)
27+
.scrollIntoView()
28+
.find('button')
29+
.contains('Install')
30+
31+
log('Force the plugins to be installed with an npm install')
32+
cy.exec(`cd ${Cypress.env('projectFolder')} && npm install`)
33+
34+
log(`Make sure ${plugin} is displayed as installed`)
35+
waitForApplication()
36+
cy.visit(pluginsPage)
37+
cy.get(`[data-plugin-package-name="${plugin}"]`)
38+
.scrollIntoView()
39+
.find('button')
40+
.contains('Uninstall')
41+
})
42+
})

cypress/e2e/utils.js

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,36 @@
1-
21
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
32

3+
const log = (message) => cy.task('log', message)
4+
45
const authenticate = () => {
56
const password = Cypress.env('password')
67
if (password) {
7-
cy.task('log', `Authenticating with ${password}`)
8+
log(`Authenticating with ${password}`)
89
cy.get('input#password').type(password)
910
cy.get('form').submit()
1011
}
1112
}
1213

1314
const waitForApplication = async (path = '/index') => {
14-
cy.task('log', `Waiting for app to restart and load ${path} page`)
15+
log(`Waiting for app to restart and load ${path} page`)
1516
cy.task('waitUntilAppRestarts')
1617
cy.visit(path)
1718
cy.get('.govuk-header__logotype-text')
1819
.should('contains.text', 'GOV.UK')
1920
}
2021

2122
const copyFile = (source, target) => {
22-
cy.task('log', `Copy ${source} to ${target}`)
23+
log(`Copy ${source} to ${target}`)
2324
cy.task('copyFile', { source, target })
2425
}
2526

2627
const deleteFile = (filename) => {
27-
cy.task('log', `Delete ${filename}`)
28+
log(`Delete ${filename}`)
2829
cy.task('deleteFile', { filename })
2930
}
3031

3132
const createFile = (filename, options) => {
32-
cy.task('log', `Create ${filename}`)
33+
log(`Create ${filename}`)
3334
cy.task('createFile', { filename, ...options })
3435
}
3536

@@ -38,7 +39,7 @@ const replaceInFile = (filename, originalText, source, newText) => {
3839
}
3940

4041
function uninstallPlugin (plugin) {
41-
cy.task('log', `Uninstalling ${plugin}`)
42+
log(`Uninstalling ${plugin}`)
4243
cy.exec(`cd ${Cypress.env('projectFolder')} && npm uninstall ${plugin}`)
4344
cy.task('pluginUninstalled', { plugin, timeout: 15000 })
4445
}
@@ -47,18 +48,19 @@ function installPlugin (plugin, version = '') {
4748
if (version) {
4849
version = '@' + version
4950
}
50-
cy.task('log', `Installing ${plugin}${version}`)
51+
log(`Installing ${plugin}${version}`)
5152
cy.exec(`cd ${Cypress.env('projectFolder')} && npm install ${plugin}${version} --save-exact `)
5253
if (plugin.startsWith('file:')) {
5354
plugin = plugin.substring(plugin.lastIndexOf('/') + 1)
5455
}
55-
cy.task('log', `Waiting for ${plugin}${version} to be installed`)
56+
log(`Waiting for ${plugin}${version} to be installed`)
5657
cy.task('pluginInstalled', { plugin, version, timeout: 15000 })
5758
}
5859

5960
module.exports = {
6061
authenticate,
6162
sleep,
63+
log,
6264
waitForApplication,
6365
copyFile,
6466
deleteFile,

lib/dev-server.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ function runNodemon (port) {
105105
script: path.join(packageDir, 'listen-on-port.js'),
106106
ignore: [
107107
'app/assets/*'
108-
]
108+
],
109+
delay: 1000
109110
}
110111

111112
const linkedDependencyDirectories = fs.readdirSync(nodeModulesPath).map(dirName => {

lib/manage-prototype-handlers.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ const {
4040

4141
async function isValidVersion (packageName, version) {
4242
const { versions = [], localVersion } = await lookupPackageInfo(packageName, version)
43-
const isVersionValid = [...versions, localVersion].includes(version)
43+
const validVersions = [...versions, localVersion]
44+
const isVersionValid = validVersions.includes(version)
4445
if (!isVersionValid) {
45-
console.log('version', version, ' is not valid, valid options are:\n\n', versions)
46+
console.log('version', version, ' is not valid, valid options are:\n\n', validVersions)
4647
}
4748
return isVersionValid
4849
}

lib/plugins/packages.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const projectPackage = require(path.join(projectDir, 'package.json'))
1414
const config = require('../config')
1515
const { getConfigForPackage } = require('../utils/requestHttps')
1616
const { getProxyPluginConfig } = require('./plugin-utils')
17+
const { sortByObjectKey } = require('../utils')
1718

1819
let packageTrackerInterval
1920

@@ -72,12 +73,21 @@ async function refreshPackageInfo (packageName, version) {
7273
return undefined
7374
}
7475

75-
const latestVersion = registryInfo ? registryInfo['dist-tags']?.latest : undefined
76+
const distTags = registryInfo ? registryInfo['dist-tags'] : undefined
77+
let latestVersion = distTags?.latest
78+
if (distTags && config.getConfig().showPrereleases) {
79+
latestVersion = Object.values(distTags)
80+
.map(version => ({ version, date: registryInfo.time[version] }))
81+
.sort(sortByObjectKey('date'))
82+
.at(-1)
83+
.version
84+
}
7685
const versions = registryInfo ? Object.keys(registryInfo.versions) : []
7786

78-
const installedPackageVersion = projectPackage.dependencies[packageName]
87+
const installedPackageVersion = packageJson && projectPackage.dependencies[packageName]
7988
const installed = !!installedPackageVersion
8089
const installedLocally = installedPackageVersion?.startsWith('file:')
90+
const installedVersion = installed ? packageJson?.version : undefined
8191

8292
let localVersion
8393

@@ -104,7 +114,6 @@ async function refreshPackageInfo (packageName, version) {
104114
pluginConfig = getProxyPluginConfig(packageName)
105115
}
106116

107-
const { version: installedVersion } = installed ? packageJson : {}
108117
if (installedLocally) {
109118
localVersion = path.resolve(installedPackageVersion.replace('file:', ''))
110119
}

lib/plugins/plugins.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const { startPerformanceTimer, endPerformanceTimer } = require('../utils/perform
4848
const { getProxyPluginConfig } = require('./plugin-utils')
4949

5050
const pkgPath = path.join(projectDir, 'package.json')
51+
const pkgLockPath = path.join(projectDir, 'package-lock.json')
5152

5253
// Generic utilities
5354
const removeDuplicates = arr => [...new Set(arr)]
@@ -255,7 +256,7 @@ function expandToIncludeShadowNunjucks (arr) {
255256
function getCurrentPlugins () {
256257
const timer = startPerformanceTimer()
257258
const pkg = fs.existsSync(pkgPath) ? fse.readJsonSync(pkgPath) : {}
258-
const dependencies = pkg.dependencies || {}
259+
const dependencies = pkg?.dependencies || {}
259260
const result = Object.keys(dependencies).filter((dependency) => fse.pathExistsSync(pathToPluginConfigFile(dependency)))
260261
endPerformanceTimer('getCurrentPlugins', timer)
261262
return result
@@ -264,7 +265,7 @@ function getCurrentPlugins () {
264265
let previousPlugins = getCurrentPlugins()
265266

266267
function watchPlugins (afterWatch) {
267-
chokidar.watch(pkgPath, {
268+
chokidar.watch(pkgLockPath, {
268269
ignoreInitial: true,
269270
disableGlobbing: true, // Prevents square brackets from being mistaken for globbing characters
270271
awaitWriteFinish: true

0 commit comments

Comments
 (0)