Skip to content

Commit

Permalink
Merge pull request #1481 from alphagov/ldeb-move-js-to-lib
Browse files Browse the repository at this point in the history
Move shared JavaScript to lib folder
  • Loading branch information
lfdebrux authored Aug 3, 2022
2 parents 735e393 + 5e94bc7 commit 5da3de9
Show file tree
Hide file tree
Showing 20 changed files with 519 additions and 46 deletions.
5 changes: 5 additions & 0 deletions __tests__/spec/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ describe('the build pipeline', () => {
})

it('copies javascript to the public folder', () => {
expect(fs.copyFileSync).toHaveBeenCalledWith(
path.join(projectDir, 'lib', 'assets', 'javascripts', 'kit.js'),
path.join('public', '_kit', 'javascripts', 'kit.js')
)

expect(fs.copyFileSync).toHaveBeenCalledWith(
path.join('app', 'assets', 'javascripts', 'application.js'),
path.join('public', 'javascripts', 'application.js')
Expand Down
33 changes: 32 additions & 1 deletion __tests__/spec/update-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const execPromise = promisify(child_process.exec)
const execFilePromise = promisify(child_process.execFile)

// This is a long-running test
jest.setTimeout(60000)
jest.setTimeout(120000)

function testSkipFailingIf (condition, ...args) {
if (condition) {
Expand Down Expand Up @@ -511,6 +511,37 @@ describe('update.sh', () => {
})
})

describe('post', () => {
let testDir, gitStatus

beforeAll(async () => {
testDir = await mktestPrototype(
'update-post', { ref: 'v12.1.1' }
)

await runScriptAndExpectSuccess('post', { testDir })

gitStatus = await execGitStatus(testDir)
})

it('updates app stylesheets', () => {
expect(gitStatus).toEqual(expect.arrayContaining([
' M app/assets/sass/application.scss',
' D app/assets/sass/application-ie8.scss',
' D app/assets/sass/unbranded-ie8.scss'
]))
})

it('updates app javascripts', () => {
expect(gitStatus).toEqual(expect.arrayContaining([
' M app/assets/javascripts/application.js',
' D app/assets/javascripts/auto-store-data.js',
' D app/assets/javascripts/jquery-1.11.3.js',
' D app/assets/javascripts/step-by-step-nav.js'
]))
})
})

it('can be run as a piped script', async () => {
const testDir = await mktestPrototype('pipe')

Expand Down
21 changes: 2 additions & 19 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,3 @@
window.GOVUKPrototypeKit = {
documentReady: function (fn) {
if (document.readyState !== 'loading') {
// IE9 support
fn()
} else {
// Everything else
document.addEventListener('DOMContentLoaded', fn)
}
}
}

// Warn about using the kit in production
if (window.console && window.console.info) {
window.console.info('GOV.UK Prototype Kit - do not use for production')
}

window.GOVUKPrototypeKit.documentReady(function () {
window.GOVUKFrontend.initAll()
window.GOVUKPrototypeKit.documentReady(() => {
// Add JavaScript here
})
3 changes: 2 additions & 1 deletion app/views/includes/scripts.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
<script src="{{scriptUrl}}"></script>
{% endfor %}

<script src="/public/_kit/javascripts/kit.js"></script>
<script src="/public/javascripts/application.js"></script>

{% if useAutoStoreData %}
<script src="/public/javascripts/auto-store-data.js"></script>
<script src="/public/_kit/javascripts/auto-store-data.js"></script>
{% endif %}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('watch application.js', () => {
const onAlert = cy.stub()
cy.on('window:alert', onAlert)

const markerText = 'window.GOVUKFrontend.initAll()'
const markerText = '// Add JavaScript here'
const newText = markerText + '\n ' + "window.alert('Test')"

cy.task('replaceTextInFile', {
Expand Down
5 changes: 5 additions & 0 deletions lib/_update/post.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const { updateJavascripts } = require('./update-javascripts')
const { updateScss } = require('./update-scss')

updateJavascripts()
updateScss()
29 changes: 29 additions & 0 deletions lib/_update/update-javascripts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const fs = require('fs').promises
const path = require('path')

const { getProjectVersion, patchUserFile } = require('./util')
const { projectDir } = require('../path-utils')

async function updateJavascripts () {
// Delete any old shared files
const appJsPath = path.join(projectDir, 'app', 'assets', 'javascripts')
await fs.unlink(path.join(appJsPath, 'auto-store-data.js')).catch(() => {})
await fs.unlink(path.join(appJsPath, 'jquery-1.11.3.js')).catch(() => {})
await fs.unlink(path.join(appJsPath, 'step-by-step-nav.js')).catch(() => {})
await fs.unlink(path.join(appJsPath, 'step-by-step-navigation.js')).catch(() => {})

const userVersion = await getProjectVersion()

// If the user already has version 13 or greater of the kit installed then
// their application.js file is all their code and we don't don't want to
// change it
if (userVersion >= '13.0.0') {
return
}

await patchUserFile(userVersion, 'app/assets/javascripts/application.js')
}

module.exports = {
updateJavascripts
}
124 changes: 124 additions & 0 deletions lib/_update/update-javascripts.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/* eslint-env jest */

const fs = require('fs')
const fsp = require('fs').promises
const path = require('path')

jest.mock('./util/fetch-original')
jest.mock('./util', () => {
const originalModule = jest.requireActual('./util')

return {
...originalModule,
getProjectVersion: jest.fn(async () => '')
}
})
const { fetchOriginal: mockFetchOriginal } = require('./util/fetch-original')
const { getProjectVersion: mockGetProjectVersion } = require('./util')
const { projectDir } = require('../path-utils')

const { updateJavascripts } = require('./update-javascripts')

const originalApplicationJs = `/* global $ */
// Warn about using the kit in production
if (window.console && window.console.info) {
window.console.info('GOV.UK Prototype Kit - do not use for production')
}
$(document).ready(function () {
window.GOVUKFrontend.initAll()
})
`
const newApplicationJs = fs.readFileSync(
path.join('app', 'assets', 'javascripts', 'application.js'),
'utf8'
)

describe('updateJavascripts', () => {
let mockCopyFile, mockReadFile, mockUnlink, mockWriteFile

beforeEach(async () => {
mockGetProjectVersion.mockResolvedValue(
'12.1.1'
)

mockFetchOriginal.mockResolvedValue(
originalApplicationJs
)

mockReadFile = jest.spyOn(fsp, 'readFile').mockResolvedValue(
newApplicationJs
)

mockCopyFile = jest.spyOn(fsp, 'copyFile').mockImplementation(async () => {})
mockUnlink = jest.spyOn(fsp, 'unlink').mockImplementation(async () => {})
mockWriteFile = jest.spyOn(fsp, 'writeFile').mockImplementation(async () => {})
})

afterEach(() => {
jest.restoreAllMocks()
})

it('replaces application.js if the user has not updated it', async () => {
// theirs
mockReadFile.mockResolvedValueOnce(
originalApplicationJs
)

await updateJavascripts()

expect(mockCopyFile).toHaveBeenCalledWith(
path.join(projectDir, 'update', 'app', 'assets', 'javascripts', 'application.js'),
path.join(projectDir, 'app', 'assets', 'javascripts', 'application.js')
)
})

it('rewrites application.js if the user has added lines to the bottom of the file', async () => {
// theirs
mockReadFile.mockResolvedValueOnce(
originalApplicationJs + '\ncallMyCode()\n'
)
// ours
mockReadFile.mockResolvedValue(
newApplicationJs
)

await updateJavascripts()

expect(mockWriteFile).toHaveBeenCalledWith(
path.join(projectDir, 'app', 'assets', 'javascripts', 'application.js'),
newApplicationJs + '\ncallMyCode()\n',
'utf8'
)
})

it('does not touch application.js if the user prototype is already on v13', async () => {
mockGetProjectVersion.mockResolvedValue(
'13.0.0'
)

await updateJavascripts()

expect(mockReadFile).not.toHaveBeenCalled()
expect(mockWriteFile).not.toHaveBeenCalled()
expect(mockCopyFile).not.toHaveBeenCalled()
})

it('removes files that have been moved from app folder', async () => {
await updateJavascripts()

expect(mockUnlink).toHaveBeenCalledWith(
path.join(projectDir, 'app', 'assets', 'javascripts', 'auto-store-data.js')
)
expect(mockUnlink).toHaveBeenCalledWith(
path.join(projectDir, 'app', 'assets', 'javascripts', 'jquery-1.11.3.js')
)
expect(mockUnlink).toHaveBeenCalledWith(
path.join(projectDir, 'app', 'assets', 'javascripts', 'step-by-step-nav.js')
)
expect(mockUnlink).toHaveBeenCalledWith(
path.join(projectDir, 'app', 'assets', 'javascripts', 'step-by-step-navigation.js')
)
})
})
16 changes: 16 additions & 0 deletions lib/_update/update-scss/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const {
appSassPatternsPath,
libSassPatternsPath,
appSassPath,
libSassPath,
removeKitSassFromApplicationSass,
removeKitSassFromAppSassPath,
removeLegacyIE8Sass
} = require('./update_scss')

module.exports.updateScss = function () {
removeKitSassFromApplicationSass()
removeKitSassFromAppSassPath(appSassPatternsPath, libSassPatternsPath)
removeKitSassFromAppSassPath(appSassPath, libSassPath)
removeLegacyIE8Sass()
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const path = require('path')
const fs = require('fs')
const { projectDir, packageDir } = require('../path-utils')
const { projectDir, packageDir } = require('../../path-utils')
const appSassPath = path.join(projectDir, 'app', 'assets', 'sass')
const appSassPatternsPath = path.join(appSassPath, 'patterns')
const applicationScssPath = path.join(appSassPath, 'application.scss')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const fs = require('fs')
const path = require('path')
const updateKit = require('./update_scss')
const { appSassPath } = require('./update_scss')
const { projectDir } = require('../path-utils')
const { projectDir } = require('../../path-utils')

describe('scripts/update-kit', () => {
afterEach(() => {
Expand Down
33 changes: 33 additions & 0 deletions lib/_update/util/fetch-original.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const https = require('https')

async function fetchOriginal (version, filePath) {
const remoteUrl = `https://raw.githubusercontent.com/alphagov/govuk-prototype-kit/v${version}/${filePath}`

let data = ''
return new Promise((resolve, reject) => {
https.get(remoteUrl, (response) => {
let error

if (response.statusCode !== 200) {
error = new Error(`could not fetch ${remoteUrl}: status code ${response.statusCode}`)
Object.assign(error, response)
response.resume()
reject(error)
}

response.setEncoding('utf8')

response.on('data', (chunk) => {
data += chunk
})

response.on('end', () => {
resolve(data)
})
})
})
}

module.exports = {
fetchOriginal
}
29 changes: 29 additions & 0 deletions lib/_update/util/fetch-original.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* eslint-env jest */

const https = require('https')
const stream = require('stream')

const { fetchOriginal } = require('./fetch-original')

describe('fetchOriginal', () => {
it('gets the contents of a file as of version from GitHub', async () => {
const mockHttpsGet = jest.spyOn(https, 'get').mockImplementation((url, callback) => {
const response = new stream.PassThrough()
response.statusCode = 200

callback(response)

response.write('foo\n')
response.write('bar\n')
response.end()
})

await expect(fetchOriginal('99.99.99', 'app/views/foo.html')).resolves.toEqual(
'foo\nbar\n'
)
expect(mockHttpsGet).toHaveBeenCalledWith(
'https://raw.githubusercontent.com/alphagov/govuk-prototype-kit/v99.99.99/app/views/foo.html',
expect.anything()
)
})
})
Loading

0 comments on commit 5da3de9

Please sign in to comment.