Skip to content

Commit

Permalink
Add update post script to update user's layout template includes
Browse files Browse the repository at this point in the history
  • Loading branch information
lfdebrux committed Aug 3, 2022
1 parent 2d5e369 commit e70f8a9
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 0 deletions.
7 changes: 7 additions & 0 deletions __tests__/spec/update-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,13 @@ describe('update.sh', () => {
' D app/assets/javascripts/step-by-step-nav.js'
]))
})

it('updates app template includes', () => {
expect(gitStatus).toEqual(expect.arrayContaining([
' M app/views/includes/head.html',
' M app/views/includes/scripts.html'
]))
})
})

it('can be run as a piped script', async () => {
Expand Down
2 changes: 2 additions & 0 deletions lib/_update/post.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const { updateJavascripts } = require('./update-javascripts')
const { updateScss } = require('./update-scss')
const { updateIncludes } = require('./update-includes')

updateJavascripts()
updateScss()
updateIncludes()
19 changes: 19 additions & 0 deletions lib/_update/update-includes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const { getProjectVersion, patchUserFile } = require('./util')

async function updateIncludes () {
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/views/includes/head.html')
await patchUserFile(userVersion, 'app/views/includes/scripts.html')
}

module.exports = {
updateIncludes
}
202 changes: 202 additions & 0 deletions lib/_update/update-includes.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/* 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 { updateIncludes } = require('./update-includes')

const originalIncludesHead = `<!--[if lte IE 8]><link href="/public/stylesheets/application-ie8.css" rel="stylesheet" type="text/css" /><![endif]-->
<!--[if gt IE 8]><!--><link href="/public/stylesheets/application.css" media="all" rel="stylesheet" type="text/css" /><!--<![endif]-->
{% for stylesheetUrl in extensionConfig.stylesheets %}
<link href="{{ stylesheetUrl }}" rel="stylesheet" type="text/css" />
{% endfor %}
`

const newIncludesHead = fs.readFileSync(
path.join(projectDir, 'app', 'views', 'includes', 'head.html'),
'utf8'
)

const originalIncludesScripts = `<!-- Javascript -->
<script src="/public/javascripts/jquery-1.11.3.js"></script>
{% for scriptUrl in extensionConfig.scripts %}
<script src="{{scriptUrl}}"></script>
{% endfor %}
<script src="/public/javascripts/application.js"></script>
{% if useAutoStoreData %}
<script src="/public/javascripts/auto-store-data.js"></script>
{% endif %}
`

const newIncludesScripts = fs.readFileSync(
path.join(projectDir, 'app', 'views', 'includes', 'scripts.html'),
'utf8'
)

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

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

mockFetchOriginal.mockRejectedValue(
new Error('fetchOriginal called more times than expected')
)

mockCopyFile = jest.spyOn(fsp, 'copyFile').mockImplementation(async () => {})
mockReadFile = jest.spyOn(fsp, 'readFile').mockResolvedValue(async () => {})
mockWriteFile = jest.spyOn(fsp, 'writeFile').mockImplementation(async () => {})
})

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

it('replaces app/views/includes/{head.html, scripts.html} if the user has not updated them', async () => {
// original head.html
mockFetchOriginal.mockResolvedValueOnce(
originalIncludesHead
)
// their head.html
mockReadFile.mockResolvedValueOnce(
originalIncludesHead
)
// our head.html
mockReadFile.mockResolvedValueOnce(
newIncludesHead
)

// original scripts.html
mockFetchOriginal.mockResolvedValueOnce(
originalIncludesScripts
)
// their scripts.html
mockReadFile.mockResolvedValueOnce(
originalIncludesScripts
)
// our scripts.html
mockReadFile.mockResolvedValueOnce(
newIncludesScripts
)

await updateIncludes()

expect(mockCopyFile).toHaveBeenCalledWith(
path.join(projectDir, 'update', 'app', 'views', 'includes', 'head.html'),
path.join(projectDir, 'app', 'views', 'includes', 'head.html')
)

expect(mockCopyFile).toHaveBeenCalledWith(
path.join(projectDir, 'update', 'app', 'views', 'includes', 'scripts.html'),
path.join(projectDir, 'app', 'views', 'includes', 'scripts.html')
)
})

it('rewrites app/views/includes/{head.html, scripts.html} if the user has added lines to the bottom of the file', async () => {
// original head.html
mockFetchOriginal.mockResolvedValueOnce(
originalIncludesHead
)
// their head.html
mockReadFile.mockResolvedValueOnce(
originalIncludesHead + '\n<link href="mystyles.css" rel="stylesheet" type="text/css" />\n'
)
// our head.html
mockReadFile.mockResolvedValueOnce(
newIncludesHead
)

// original scripts.html
mockFetchOriginal.mockResolvedValueOnce(
originalIncludesScripts
)
// their scripts.html
mockReadFile.mockResolvedValueOnce(
originalIncludesScripts + '\n<script>callMyCode()</script>\n'
)
// our scripts.html
mockReadFile.mockResolvedValueOnce(
newIncludesScripts
)

await updateIncludes()

expect(mockWriteFile).toHaveBeenCalledWith(
path.join(projectDir, 'app', 'views', 'includes', 'head.html'),
newIncludesHead + '\n<link href="mystyles.css" rel="stylesheet" type="text/css" />\n',
'utf8'
)

expect(mockWriteFile).toHaveBeenCalledWith(
path.join(projectDir, 'app', 'views', 'includes', 'scripts.html'),
newIncludesScripts + '\n<script>callMyCode()</script>\n',
'utf8'
)
})

it('rewrites app/views/includes/scripts.html even if it cannot rewrite head.html', async () => {
// original head.html
mockFetchOriginal.mockResolvedValueOnce(
originalIncludesHead
)
// their head.html
mockReadFile.mockResolvedValueOnce(
'\n<link href="mystyles.css" rel="stylesheet" type="text/css" />\n'
)
// our head.html
mockReadFile.mockResolvedValueOnce(
newIncludesHead
)

// original scripts.html
mockFetchOriginal.mockResolvedValueOnce(
originalIncludesScripts
)
// their scripts.html
mockReadFile.mockResolvedValueOnce(
originalIncludesScripts + '\n<script>callMyCode()</script>\n'
)
// our scripts.html
mockReadFile.mockResolvedValueOnce(
newIncludesScripts
)

const mockConsoleWarn = jest.spyOn(global.console, 'warn').mockImplementation(() => {})

await updateIncludes()

expect(mockWriteFile).not.toHaveBeenCalledWith(
path.join(projectDir, 'app', 'views', 'includes', 'head.html'),
newIncludesHead + '\n<link href="mystyles.css" rel="stylesheet" type="text/css" />\n',
'utf8'
)

expect(mockWriteFile).toHaveBeenCalledWith(
path.join(projectDir, 'app', 'views', 'includes', 'scripts.html'),
newIncludesScripts + '\n<script>callMyCode()</script>\n',
'utf8'
)

expect(mockConsoleWarn).toHaveBeenCalledTimes(1)
})
})

0 comments on commit e70f8a9

Please sign in to comment.