Files
cypress/packages/server/test/unit/plugins/preprocessor_spec.js
Matt Henkes 62f58e00ec chore: Add open telemetry to cypress to allow us to monitor the performance of the app overtime (#26305)
* initial commit, a kinda working prototype

* Ready to test in CI

* "SyntaxError: Cannot use import statement outside a module" I blame VS code for always inserting the wrong dependency

* try using built js instead of the ts file

* typescript fixes?

* get version correctly, don't use optional chaining in child process.

* trying this, idk

* try running telemetry for driver-integration-tests-chrome

* fix missing spans, add more attributes for some spans

* fix missing spans and add suite spans

* types

* Remove un-used require

* remove spans for describe blocks in favor of the full title for tests

* migrate to sync resource discovery, start new custom exporters for spans

* encrypted

* localhost

* don't do things on child process

* latest changes

* update server start span time / add v8 snapshot span & update command span names

* prepare for sync

* don't send blank key

* make telemetry work again for sending directly to honeycomb

* web-socket exporter

* Add in IPC exporter and message the child process before disconnecting

* Use the cloud api by default

* move cloud span exporter into telemetry package

* shutdown fixes

* fix enabled

* improve types

* run in ci

* yml is the worst

* type!

* add spans for timing insights for visible areas of improvement

* type errors

* lets try sending data to staging

* types

* types again

* remove problematic attributes

* clean up exporters

* i like this better even though it doesn't seem to matter much

* some self review cleanup

* Update comment

* add debug messages

* mocha tests

* actually exit with the right code... oops

* simple mistake... have to look into how to fix with ts...

* try this i guess

* don't return undefined

* read me diagram

* color?

* no rect

* moar diagram

* docs!

* formatting

* build more binaries

* Supposedly fix cypress in cypress test failures

* test 'fixes'

* try this instead

* do not transpile cypress packages dir

* lets try escaping our regex string

* Add some diagnostics to help test the built binary....

* try a more complex solution

* fix tests probably

* just ignore the specific file

* fix unit tests

* cr updates

* Apply suggestions from code review

Co-authored-by: Matt Schile <mschile@cypress.io>
Co-authored-by: Bill Glesias <bglesias@gmail.com>

* Pr updates

* don't change the command queue

* move encoding and decoding telemetry context for ipc to the telemetry package

* build darn it

* plead for mercy from the testing gods, i merely wished to have named test reports, but clearly i have overreached.

* pr updates, send record key

* pr review

* optional chaining fails tests

* Apply suggestions from code review

Co-authored-by: Bill Glesias <bglesias@gmail.com>

* tests for cloud-span-exporter

* bad merge

* adding tests for the remaining exporters

* note

* docs

* Correctly set test under the current run span for component testing

* gate sending the message.

* pr updates

* finally, fingers crossed.

---------

Co-authored-by: Emily Rohrbough <emilyrohrbough@yahoo.com>
Co-authored-by: Matt Schile <mschile@cypress.io>
Co-authored-by: Bill Glesias <bglesias@gmail.com>
2023-04-08 21:18:02 -05:00

186 lines
5.7 KiB
JavaScript

require('../../spec_helper')
const Fixtures = require('@tooling/system-tests')
const path = require('path')
const appData = require(`../../../lib/util/app_data`)
const plugins = require(`../../../lib/plugins`)
const preprocessor = require(`../../../lib/plugins/preprocessor`)
describe('lib/plugins/preprocessor', () => {
beforeEach(function () {
Fixtures.scaffold()
this.todosPath = Fixtures.projectPath('todos')
this.filePath = 'path/to/test.coffee'
this.fullFilePath = path.join(this.todosPath, this.filePath)
this.testPath = path.join(this.todosPath, 'test.coffee')
this.localPreprocessorPath = path.join(this.todosPath, 'prep.coffee')
this.plugin = sinon.stub().returns(new Promise((resolve) => resolve('/path/to/output.js')))
plugins.registerEvent('file:preprocessor', this.plugin)
preprocessor.close()
this.config = {
preprocessor: 'custom',
projectRoot: this.todosPath,
}
})
context('#getFile', () => {
it('executes the plugin with file path', function () {
preprocessor.getFile(this.filePath, this.config)
expect(this.plugin).to.be.called
expect(this.plugin.lastCall.args[0].filePath).to.equal(this.fullFilePath)
})
it('executes the plugin with output path', function () {
preprocessor.getFile(this.filePath, this.config)
const expectedPath = appData.projectsPath(appData.toHashName(this.todosPath), 'bundles', this.filePath)
expect(this.plugin.lastCall.args[0].outputPath).to.equal(expectedPath)
})
it('returns a promise resolved with the plugin\'s outputPath', function () {
return preprocessor.getFile(this.filePath, this.config).then((filePath) => {
expect(filePath).to.equal('/path/to/output.js')
})
})
it('emits \'file:updated\' with filePath when \'rerun\' is emitted', function () {
const fileUpdated = sinon.spy()
preprocessor.emitter.on('file:updated', fileUpdated)
preprocessor.getFile(this.filePath, this.config)
this.plugin.lastCall.args[0].emit('rerun')
expect(fileUpdated).to.be.calledWith(this.fullFilePath)
})
it('invokes plugin again when isTextTerminal: false', function () {
this.config.isTextTerminal = false
preprocessor.getFile(this.filePath, this.config)
preprocessor.getFile(this.filePath, this.config)
expect(this.plugin).to.be.calledTwice
})
it('does not invoke plugin again when isTextTerminal: true', function () {
this.config.isTextTerminal = true
preprocessor.getFile(this.filePath, this.config)
preprocessor.getFile(this.filePath, this.config)
expect(this.plugin).to.be.calledOnce
})
})
context('#removeFile', () => {
it('emits \'close\'', function () {
preprocessor.getFile(this.filePath, this.config)
const onClose = sinon.spy()
this.plugin.lastCall.args[0].on('close', onClose)
preprocessor.removeFile(this.filePath, this.config)
expect(onClose).to.be.called
})
it('emits \'close\' with file path on base emitter', function () {
const onClose = sinon.spy()
preprocessor.emitter.on('close', onClose)
preprocessor.getFile(this.filePath, this.config)
preprocessor.removeFile(this.filePath, this.config)
expect(onClose).to.be.calledWith(this.fullFilePath)
})
})
context('#close', () => {
it('emits \'close\' on config emitter', function () {
preprocessor.getFile(this.filePath, this.config)
const onClose = sinon.spy()
this.plugin.lastCall.args[0].on('close', onClose)
preprocessor.close()
expect(onClose).to.be.called
})
it('emits \'close\' on base emitter', function () {
const onClose = sinon.spy()
preprocessor.emitter.on('close', onClose)
preprocessor.getFile(this.filePath, this.config)
preprocessor.close()
expect(onClose).to.be.called
})
})
context('#clientSideError', () => {
beforeEach(() => {
return sinon.stub(console, 'error')
}) // keep noise out of console
it('send javascript string with the error', () => {
expect(preprocessor.clientSideError('an error')).to.equal(`\
(function () {
Cypress.action("spec:script:error", {
type: "BUNDLE_ERROR",
error: "an error"
})
}())\
`)
})
it('does not replace new lines with {newline} placeholder', () => {
expect(preprocessor.clientSideError('with\nnew\nlines')).to.include('error: "with\\nnew\\nlines"')
})
it('does not remove command line syntax highlighting characters', () => {
expect(preprocessor.clientSideError('[30mfoo[100mbar[7mbaz')).to.include('error: "[30mfoo[100mbar[7mbaz"')
})
})
context('#errorMessage', () => {
it('handles error strings', () => {
expect(preprocessor.errorMessage('error string')).to.include('error string')
})
it('handles standard error objects and sends the stack', () => {
const err = new Error()
err.stack = 'error object stack'
expect(preprocessor.errorMessage(err)).to.equal('error object stack')
})
it('sends err.annotated if stack is not present', () => {
const err = {
stack: undefined,
annotated: 'annotation',
}
expect(preprocessor.errorMessage(err)).to.equal('annotation')
})
it('sends err.message if stack and annotated are not present', () => {
const err = {
stack: undefined,
message: 'message',
}
expect(preprocessor.errorMessage(err)).to.equal('message')
})
it('does not remove stack lines', () => {
expect(preprocessor.errorMessage('foo\n at what.ever (foo 23:30)\n baz\n at where.ever (bar 1:5)'))
.to.equal('foo\n at what.ever (foo 23:30)\n baz\n at where.ever (bar 1:5)')
})
})
})