Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore(graphcache): add way we could go forward in e2e testing exchanges/... (#2794)

authored by

Jovi De Croock and committed by
GitHub
f3dac26f f33ebf49

+285
+85
.github/workflows/ci.yml
··· 50 50 run: yarn run lint 51 51 - name: Unit Tests 52 52 run: yarn run test --maxWorkers=2 53 + 54 + react-e2e: 55 + name: React end-to-end tests 56 + runs-on: ubuntu-latest 57 + timeout-minutes: 10 58 + steps: 59 + - name: Checkout Repo 60 + uses: actions/checkout@v3 61 + with: 62 + fetch-depth: 0 63 + - name: Setup Node 64 + uses: actions/setup-node@v3 65 + with: 66 + node-version: '16' 67 + - name: Get Yarn cache directory 68 + id: yarn-cache-dir-path 69 + run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT 70 + 71 + - name: Use Yarn cache 72 + uses: actions/cache@v3 73 + id: yarn-cache 74 + with: 75 + path: | 76 + ~/.cache/Cypress 77 + ${{ steps.yarn-cache-dir-path.outputs.dir }} 78 + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 79 + restore-keys: | 80 + ${{ runner.os }}-yarn- 81 + - name: Use node_modules cache 82 + id: node-modules-cache 83 + uses: actions/cache@v3 84 + with: 85 + path: node_modules 86 + key: ${{ runner.os }}-node-modules-${{ hashFiles('**/yarn.lock') }} 87 + - name: Install Dependencies 88 + if: | 89 + steps.yarn-cache.outputs.cache-hit != 'true' || 90 + steps.node-modules-cache.outputs.cache-hit != 'true' 91 + run: yarn install --prefer-offline --frozen-lockfile --non-interactive --silent 53 92 - name: Build 54 93 run: yarn workspace @urql/core build 55 94 - name: e2e tests 🧪 ··· 57 96 with: 58 97 command: yarn cypress run-ct 59 98 working-directory: packages/react-urql 99 + 100 + graphcache-e2e: 101 + name: Graphcache end-to-end tests 102 + runs-on: ubuntu-latest 103 + timeout-minutes: 10 104 + steps: 105 + - name: Checkout Repo 106 + uses: actions/checkout@v3 107 + with: 108 + fetch-depth: 0 109 + - name: Setup Node 110 + uses: actions/setup-node@v3 111 + with: 112 + node-version: '16' 113 + - name: Get Yarn cache directory 114 + id: yarn-cache-dir-path 115 + run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT 116 + 117 + - name: Use Yarn cache 118 + uses: actions/cache@v3 119 + id: yarn-cache 120 + with: 121 + path: | 122 + ~/.cache/Cypress 123 + ${{ steps.yarn-cache-dir-path.outputs.dir }} 124 + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 125 + restore-keys: | 126 + ${{ runner.os }}-yarn- 127 + - name: Use node_modules cache 128 + id: node-modules-cache 129 + uses: actions/cache@v3 130 + with: 131 + path: node_modules 132 + key: ${{ runner.os }}-node-modules-${{ hashFiles('**/yarn.lock') }} 133 + - name: Install Dependencies 134 + if: | 135 + steps.yarn-cache.outputs.cache-hit != 'true' || 136 + steps.node-modules-cache.outputs.cache-hit != 'true' 137 + run: yarn install --prefer-offline --frozen-lockfile --non-interactive --silent 138 + - name: Build 139 + run: yarn workspace @urql/core build && yarn workspace urql build && yarn workspace @urql/exchange-execute build 140 + - name: e2e tests 🧪 141 + uses: cypress-io/github-action@v4 142 + with: 143 + command: yarn cypress run-ct 144 + working-directory: exchanges/graphcache 60 145 61 146 build: 62 147 name: Build
+7
exchanges/graphcache/cypress.json
··· 1 + { 2 + "video": false, 3 + "component": { 4 + "componentFolder": ".", 5 + "testFiles": "**/e2e-tests/*spec.tsx" 6 + } 7 + }
+5
exchanges/graphcache/cypress/fixtures/example.json
··· 1 + { 2 + "name": "Using fixtures to represent data", 3 + "email": "hello@cypress.io", 4 + "body": "Fixtures are a great way to mock data for responses to routes" 5 + }
+15
exchanges/graphcache/cypress/plugins/index.js
··· 1 + // eslint-disable-next-line 2 + const { startDevServer } = require('@cypress/vite-dev-server'); 3 + // eslint-disable-next-line 4 + const path = require('path'); 5 + 6 + /** 7 + * @type {Cypress.PluginConfig} 8 + */ 9 + module.exports = (on, _config) => { 10 + on('dev-server:start', options => 11 + startDevServer({ 12 + options, 13 + }) 14 + ); 15 + };
+25
exchanges/graphcache/cypress/support/commands.js
··· 1 + // *********************************************** 2 + // This example commands.js shows you how to 3 + // create various custom commands and overwrite 4 + // existing commands. 5 + // 6 + // For more comprehensive examples of custom 7 + // commands please read more here: 8 + // https://on.cypress.io/custom-commands 9 + // *********************************************** 10 + // 11 + // 12 + // -- This is a parent command -- 13 + // Cypress.Commands.add('login', (email, password) => { ... }) 14 + // 15 + // 16 + // -- This is a child command -- 17 + // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 18 + // 19 + // 20 + // -- This is a dual command -- 21 + // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 22 + // 23 + // 24 + // -- This will overwrite an existing command -- 25 + // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
+20
exchanges/graphcache/cypress/support/index.js
··· 1 + // *********************************************************** 2 + // This example support/index.js is processed and 3 + // loaded automatically before your test files. 4 + // 5 + // This is a great place to put global configuration and 6 + // behavior that modifies Cypress. 7 + // 8 + // You can change the location of this file or turn off 9 + // automatically serving support files with the 10 + // 'supportFile' configuration option. 11 + // 12 + // You can read more here: 13 + // https://on.cypress.io/configuration 14 + // *********************************************************** 15 + 16 + // Import commands.js using ES2015 syntax: 17 + import './commands'; 18 + 19 + // Alternatively you can use CommonJS syntax: 20 + // require('./commands')
+128
exchanges/graphcache/e2e-tests/updates.spec.tsx
··· 1 + /// <reference types="cypress" /> 2 + 3 + import * as React from 'react'; 4 + import { mount } from '@cypress/react'; 5 + import { 6 + Provider, 7 + createClient, 8 + gql, 9 + useQuery, 10 + useMutation, 11 + dedupExchange, 12 + debugExchange, 13 + } from 'urql'; 14 + import { executeExchange } from '@urql/exchange-execute'; 15 + import { buildSchema } from 'graphql'; 16 + 17 + import { cacheExchange } from '../src'; 18 + 19 + const schema = buildSchema(` 20 + type Todo { 21 + id: ID! 22 + text: String! 23 + } 24 + 25 + type Query { 26 + todos: [Todo]! 27 + } 28 + 29 + type Mutation { 30 + updateTodo(id: ID! text: String!): Todo! 31 + } 32 + `); 33 + 34 + const todos: Array<{ id: string; text: string }> = [ 35 + { id: '1', text: 'testing urql' }, 36 + ]; 37 + 38 + const rootValue = { 39 + todos: () => { 40 + return todos; 41 + }, 42 + updateTodo: args => { 43 + const todo = todos.find(x => x.id === args.id); 44 + if (!todo) throw new Error("Can't find todo!"); 45 + todo.text = args.text; 46 + return todo; 47 + }, 48 + }; 49 + 50 + describe('Graphcache updates', () => { 51 + let client; 52 + beforeEach(() => { 53 + client = createClient({ 54 + url: 'https://trygql.formidable.dev/graphql/basic-pokedex', 55 + exchanges: [ 56 + dedupExchange, 57 + cacheExchange({}), 58 + debugExchange, 59 + executeExchange({ schema, rootValue }), 60 + ], 61 + }); 62 + }); 63 + 64 + const TodosQuery = gql` 65 + query { 66 + todos { 67 + id 68 + text 69 + } 70 + } 71 + `; 72 + 73 + const UpdateMutation = gql` 74 + mutation($id: ID!, $text: String!) { 75 + updateTodo(id: $id, text: $text) { 76 + id 77 + text 78 + } 79 + } 80 + `; 81 + 82 + it('Can automatically update entities who have been queried', () => { 83 + const Todos = () => { 84 + const [result] = useQuery({ query: TodosQuery }); 85 + const [, update] = useMutation(UpdateMutation); 86 + 87 + if (result.fetching) return <p>Loading...</p>; 88 + 89 + return ( 90 + <main> 91 + <ul id="todos-list"> 92 + {result.data.todos.map(todo => ( 93 + <li key={todo.id}> 94 + {todo.text} 95 + <button 96 + id={`update-${todo.id}`} 97 + onClick={() => { 98 + update({ id: todo.id, text: todo.text + '_foo' }); 99 + }} 100 + > 101 + Update {todo.id} 102 + </button> 103 + </li> 104 + ))} 105 + </ul> 106 + </main> 107 + ); 108 + }; 109 + 110 + mount( 111 + <Provider value={client}> 112 + <Todos /> 113 + </Provider> 114 + ); 115 + 116 + const target = { ...todos[0] }; 117 + cy.get('#todos-list > li').then(items => { 118 + expect(items.length).to.equal(todos.length); 119 + }); 120 + cy.get('#update-' + target.id).click(); 121 + 122 + cy.wait(500); 123 + cy.get('#todos-list > li').then(items => { 124 + expect(items.length).to.equal(todos.length); 125 + expect(items[0].innerText).to.contain(target.text + '_foo'); 126 + }); 127 + }); 128 + });