Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add template verification tests #205

Merged
merged 2 commits into from
Apr 13, 2021

Conversation

jmulcahey-twilio
Copy link
Contributor

Description

Defines a set of CI-only template verifications that run for all of the apps in the repository. The following properties are checked:

  • The functions subdirectory exists and contains at least one file.
  • That assets/index.html exists.
  • The tests subdirectory exists and contains at least one file.
  • The .env file exists, is parseable, and all of its variables have a description field, and any variables named TWILIO_*_WEBHOOK_URL are not configurable.
  • package.json exists in the root of the app, and its contents are parseable as a Javascript object literal of some form.
  • For assets/index.html, an attempt is made to detect new-style index.html files (by searching them for ce-paste-theme.css) and ensuring they contain an APP_INFO_V2 comment.

I decided to implement these verifications on top of Jest, with the tests enabled unless the environment variable CI=1. Jest had some advantages that made it attractive for this use case:

  • It supports automatic task parallelization.
  • Its output is familiar to developers, exposes a high level of debugging information including test backtraces, is automatically parsed by several CI interfaces and editors, and can provide a rich view of what each verification task is doing and why errors have occurred.
  • We already use it.

To prevent these verifications from running on every invocation of npm test or jest, I've gated them behind an environment variable, which seems to be one of the only mechanisms Jest supports for enabling and disabling test suites dynamically. The current choice of CI=1 ensures the CI's current npm test step will run these additional tests, but if we want more granular control over when they run, we can change the environment variable to something else (IE, TWILIO_CI_VERIFY=1) and use the npm run ci:verify-templates script I've defined to run these verification tasks.

Checklist

  • I ran npm test locally and it passed without errors.
  • I acknowledge that all my contributions will be made under the project's license.

Related issues

const fs = require('fs');
const { parser } = require('configure-env');

const excludedPaths = ['node_modules', 'test', 'coverage', 'docs'];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this also include blank, and possibly some of the other apps that are not quick deployable yet?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like including blank in this list, since it's intentionally non-QD. For the rest, I want to define a skipList or similar array that will contain the names of templates that aren't QD yet, but will be down the line. Eventually skipList will be empty, and we'll remove it from the test suite.

});

it('should be parseable', async () => {
const result = parser.parseFile(envFile);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be const result = await parser.parseFile(envFile); and then remove the await before the expect

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're synonymous, but I changed it to your suggestion for consistency with the other .env tests.

const result = await parser.parseFile(envFile);

result.variables.forEach((v) => {
if(!v.description) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason not to use the expect framework here? something like

result.variables.forEach((v) => expect(v.description).toBeTruthy())

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it this way to get Jest to print a custom error message that calls out the specific variable name that doesn't have a description, since the default assert error is a bit confusing without it. Otherwise, there's unfortunately no way to get expect to report a custom error message out of the box. I can pull in one of the Jest plugins that adds this capability if you'd prefer a more Jest-like solution; I didn't know if this was a pattern we wanted to use elsewhere, so I hesitated initially to pull in a devDependency for this.

const result = await parser.parseFile(envFile);
const varRegex = /^TWILIO_.*_WEBHOOK_URL$/;

result.variables
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it make more sense to filter for values matching the regex pattern then check for those configurable values to be falsy? Something like

result.variables
  .filter((v) => varRegex.test(v.key))
  .forEach((v) => expect(v.configurable).toBeFalsy())

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, this is cleaner and probably faster.

// These tests run in a CI context and verify that some important guarantees
// hold for all the functions in the repository.

if(process.env.CI) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was your thinking around not making these not as part of the standard npm test suite?

I feel like in some ways this might be more annoying to a developer to think they've passed all their tests locally, only to fail in the pr due to some mysterious suite of tests

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial understanding of this work was that these would run just for PR validation, probably to avoid slowing down the main test suite too much. That said, on my local system these execute in less than a second; I can definitely get behind adding these to the main test suite (possibly replacing all-templates.test.js with this file) if there's no objections to having them there.

also makes verifications run on every `npm test`, not just if CI=1
Comment on lines +23 to +27
(file) =>
file.isDirectory() &&
!file.name.startsWith('.') &&
!file.name.startsWith('_') &&
!excludedPaths.includes(file.name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the indentation in this file is 4 and I think the rest of the project should be two if I'm not mistaken.

fs.access(envFile, fs.constants.F_OK, (err) => {
expect(err).toBeFalsy();
done();
describe('CI template verification', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: remove CI from the description here since its now part of the general test suite

@jmulcahey-twilio jmulcahey-twilio changed the title feat(CI): Add CI-only template verification feat(CI): Add template verification tests Apr 9, 2021
@dkundel dkundel changed the title feat(CI): Add template verification tests test: add template verification tests Apr 13, 2021
@dkundel dkundel merged commit ab1244f into twilio-labs:main Apr 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants