Files
cypress/packages/data-context
Bill Glesias b85dd752f2 dependency: update to electron 25 and node 18 (#27715)
* feat: update to electron 25 and bump node dependencies. need to remove
custom docker image

* chore: update node versions to 18+ [run ci]

* chore: bump @types/node from v16 to v18 and bump the typescript supported CLI version from 3.9 to 4.4

* update mock-fs to 5.2.0 to fix BigInt issue (see https://github.com/tschaub/mock-fs/releases/tag/v5.1.4) [run ci]

* chore: update electron integrity check to pass create binary job

* chore: fix issues with achrinza/node-ipc not yet having node 18 engine support (only up to 17 by patching from 9.2.2 to 9.2.5 as seen in https://github.com/achrinza/node-ipc/pull/38. vue/cli-service is not maintained and we should migrate these over to vue create at some point in the near future to get rid of these resolutions

* allow for TLSv1 tests to work with node 18 as the express server running node 18 with tlsv1 needs to allow legacy ciphers

* chore: update snyk workflows to use node 18

* chore: add changelog

* update timeout

* more cleanup during binary build

* bump cache and run ci. include ignore engines for rwa and get rid of
16.16 image references

* chore: update FF tests to 115 as serialization now works with errors and click events do not get fired on buttons being typed into

* chore: don't error when symlink already exists

* chore: fix serialization test for newer versions of firefox

* chore: fix CI config

* chore: fix chrome system tests to work with chrome 114. updates mostly caused by bugs in screen height in chrome. see https://bugs.chromium.org/p/chromium/issues/detail?id=1416398

* chore: test binary against vite update in RWA

* remove wait for RWA as it shouldnt be needed for vite. link example recipes update to node 18

chore: remove commented out code

* chore: print message when DISABLE_SNAPSHOT_REQUIRE is set

* chore: clean out unneeded dependencies always

* chore: remove trailing space

* fix: propagate click events for enter and typing on firefox 106 or later

* chore: fix changelog failures

* fix: correctly simulate click events for buttons on keyup and space type  in Firefox versions greater than 91 and simulate click for buttons on enter in Firefox versions greater than or equal to 106

* chore: add documentation to type to clarify firefox synthetic events

* chore: update protocol snapshot as order or log messages seems to have changed

* update comments

* sort commandLogChanged events for protocol

* chore: remove PR ids from CRA and CER as the PRs are merged into develop

---------

Co-authored-by: Ryan Manuel <ryanm@cypress.io>
Co-authored-by: Chris Breiding <chrisbreiding@gmail.com>
Co-authored-by: Matt Schile <mschile@cypress.io>
2023-09-07 15:26:09 -04:00
..

@packages/data-context

Centralized data access for the Cypress application

Directories & Concepts

There are several directories in src:

  • actions
  • codegen
  • data
  • gen
  • sources
  • util

The main ones you need to know about are data, sources and actions.

Here are some general guidelines associated with each, and an example showing how they are used together.

Data

This contains the interfaces that describe the top level data (called coreData) that is exposed and used by launchpad and app. Secondary data that isn't exposed to the outside world (temporary states, flags, etc) is usually in a Source. Sources are also used to derive data.

If you want to update Data, you use an Action (see below).

Sources

The sources directory contains what can be thought of as "read only" and "derived" data. Each one is namespaced based on the kind of data it's associated with, for example Project, Browser, Settings, etc. Sources can access the ctx (type DataContext, see DataContext.ts), using this.ctx.

If you want to update something in a Source, or in coreData, you want to do it using an Action.

Actions

Actions are where mutative and destructive operations live. To make this predictable and changes each to track, updating this.ctx.coreData should be done via an Action and use this.ctx.update, which receives the current coreData as the first argument.

Example

In this example, we will load some specs for a project and persist them. We will use a Source to derive any specs with the characters "foo" in the filename. This shows how Data, Sources and Actions are connected.

1. Define Data data/coreData

First we define the type in CoreDataShape and set the initial value in makeCoreData.

export interface CoreDataShape {
  specs: string[]
}

// ...

export function makeCoreData (modeOptions: Partial<AllModeOptions> = {}): CoreDataShape {
  return {
    // ...
    specs: [],
  }
}

This is where the actual value will be saved.

2. Define Action to Update Specs

We need some way to update the value. For this, we are defining a new SpecActions class inside of actions and updating the coreData with this.ctx.update.

import type { DataContext } from '..'
import globby from 'globby'

export class SpecActions {
  constructor (private ctx: DataContext) {}

  async findSpecs () {
    const specs = await globby('./**/*.spec.js')
    this.ctx.update(coreData => {
      coreData.specs = specs
    })
  }
}

Note: If you added a new Action file, you will also need to add it to DataActions.ts, although this isn't very common.

import type { DataContext } from '.'
import {
  // ...
  SpecActions 
} from './actions'
import { cached } from './util'

export class DataActions {
  constructor (private ctx: DataContext) {}
  
  // ...

  @cached
  get specs () {
    return new SpecActions(this.ctx)
  }
}

3. Derive the Data with a Source

In this example we only want to expose specs with foo in the name. We can derive this using a Source. This will be a new Source call SpecDataSource, but you can use an existing one if it makes sense.

import type { DataContext } from '..'

export class SpecDataSource {
  constructor (private ctx: DataContext) {}

  fooSpecs () {
    return this.ctx.coreData.specs.find(spec => spec.includes('foo'))
  }
}

If you added a new Source, you need to add it to DataContext.ts.

import { SpecDataSource } from './sources/SpecDataSource'

export class DataContext {

  // ...

  @cached
  get specs () {
    return new SpecDataSource(this)
  }
}

4. (Bonus) Expose via GraphQL

You might want to expose your new Data or Source via GraphQL. It's easy, since GraphQL also has access ctx as the third argument to the resolvers. For example, we can expose specs and fooSpecs in gql-Query.ts like this:

export const Query = objectType({
  definition (t) {

    // ...

    t.list.string('specs', {
      description: 'A list of specs',
      resolve: (source, args, ctx) => {
        return ctx.coreData.specs
      },
    })

    t.list.string('fooSpecs', {
      description: 'A list of specs containing foo',
      resolve: (source, args, ctx) => {
        return ctx.specs.fooSpecs()
      },
    })
  }
})