Cannot import module from Cypress spec file

Viewed 300

I am trying to use the @peculiar/x509 library to decode a CSR to use some of the information in my tests. The tests are using Cypress.

Here is an extract of my code:

import * as x509 from '@peculiar/x509';
    
const request = {
  certificateSigningRequest: `-----BEGIN CERTIFICATE REQUEST-----
...
-----END CERTIFICATE REQUEST-----`,
};
    
describe('PKI', () => { 
  it('works', () => {
    console.log(x509);
    const stringPEM = request.certificateSigningRequest
      .replace(/(-----(BEGIN|END) CERTIFICATE REQUEST-----|\n)/g, "");
    const cert = new x509.X509Certificate(stringPEM);
    console.log(cert.subject);
    
    return;
    // Stuff I want to test
  });    
});

When I try to log the x509 variable it returns an empty object.
And on the const cert = new x509.X509Certificate(stringPEM); line, I get an error:

x509.X509Certificate is not a constructor.

If I try to set up a simple project with a Typescript file to import the library and just log the x509 variable, it displays all the exports correctly.

I can't figure why it behaves like that with Cypress, so any help is appreciated.

EDIT: Diving a bit more into how Cypress works, I now understand that my assumption about the spec files running/controlled in a Node process was wrong. Spec files are running in the browser. So I would need to inject the browser version of the library in the spec file. This can be done via the plugin API of Cypress, because it runs in the Cypress node process.

2 Answers

You can import a specific build, either x509.es.js or x509.cjs.js and your code works. The base @peculiar/x509 is for <script> inclusion.

One thing, the BEGIN and END tokens need to remain in the request for it to be recognized.

import * as x509 from '@peculiar/x509/build/x509.es.js'
// const x509 = require('@peculiar/x509/build/x509.cjs.js')  // alternative

// hard left for multiline strings, otherwise request is not correctly formatted
const request = {
  certificateSigningRequest: `-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----`,
};

// copied from @peculiar/x509 to verify format - not necessary for test
const isPem = (data) => {
  return typeof data === "string"
    && /-{5}BEGIN [A-Z0-9 ]+-{5}([a-zA-Z0-9=+/\n\r]+)-{5}END [A-Z0-9 ]+-{5}/g.test(data);
}
console.log(isPem(request.certificateSigningRequest))

describe('PKI', () => {

  it('works', () => {
    console.log(x509);
    const stringPEM = request.certificateSigningRequest // leave in BEGIN and END
    const cert = new x509.X509Certificate(stringPEM);
    console.log(cert.subject);    // prints e.g. "CN=Test certificate, E=some@email.net"

    return;
    // Stuff I want to test
  });

});

Possibly due to NodeJS version issue.

The X509Certificate was added recently in NodeJS version 15.6.0. Changelog here. So it requires that version. It might have worked on your simple project because of a newer NodeJS version.

And by default, Cypress is using its bundled NodeJS version, which since Cypress version 7.0.0 to 8.2.0, it's using bundled NodeJS version 14.16.0, as per the changelog here:

The bundled Node.js version was upgraded from 12.18.3 to 14.16.0.

So you can try changing/overriding the bundled NodeJS version in Cypress configuration to version 15.6.0, as per this configuration:

nodeVersion

Related