Skip to content

Commit

Permalink
Merge branch 'main' into feat/cli-json-flag
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt committed Jan 9, 2025
2 parents 10ff908 + 817c4e7 commit 0a00cc9
Show file tree
Hide file tree
Showing 78 changed files with 3,151 additions and 3,597 deletions.
5 changes: 5 additions & 0 deletions .changeset/big-experts-melt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphql-hive/cli': minor
---

Added subgraph type to schema:fetch cmd to print subgraph details
5 changes: 5 additions & 0 deletions .changeset/five-yaks-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'hive': patch
---

Resolve the issue where the laboratory mocked endpoint consistently returns: "Please publish your first schema to Hive."
7 changes: 7 additions & 0 deletions .changeset/grumpy-lemons-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'hive': minor
---

Adds a response validation of the POST https://slack.com/api/oauth.v2.access request.

This request is made when connecting Slack to Hive. This is to ensure that the response is a JSON object and that it contains the expected keys and provide informative error messages if it does not.
7 changes: 7 additions & 0 deletions .changeset/young-peas-battle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'hive': patch
---

Fix editor state and operation handling in Laboratory.

When opening a new tab or selecting a saved operation, the editor incorrectly populated the query, defaulting to the active query. This made it impossible to view the selected operation. Additionally, the submit button for saving an operation was always disabled, even when the form was in a valid state.
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ module.exports = {
extends: 'plugin:cypress/recommended',
rules: {
'cypress/no-unnecessary-waiting': 'off',
'cypress/unsafe-to-chain-command': 'off',
},
},
],
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ runs:
id: pnpm
run: |
PNPM_VERSION=$(cat package.json | jq -r '.packageManager' | awk -F@ '{print $2}')
PNPM_VERSION=${PNPM_VERSION:-8}
PNPM_VERSION=${PNPM_VERSION:-9}
echo "Using PNPM version $PNPM_VERSION"
echo "version=$PNPM_VERSION" >> $GITHUB_OUTPUT
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/build-and-dockerize.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ jobs:

- name: configure docker buildx
if: ${{ inputs.dockerize }}
uses: docker/setup-buildx-action@v3.7.1
uses: docker/setup-buildx-action@v3.8.0

- name: login to docker registry
if: ${{ inputs.dockerize }}
Expand Down Expand Up @@ -146,7 +146,7 @@ jobs:
timeout-minutes: 60
id: docker-bake
if: ${{ inputs.dockerize }}
uses: docker/bake-action@v5.10.0
uses: docker/bake-action@v6.0.0
env:
DOCKER_REGISTRY: ${{ inputs.registry }}/${{ inputs.imageName }}/
COMMIT_SHA: ${{ inputs.imageTag }}
Expand All @@ -163,6 +163,7 @@ jobs:
push: true
files: docker/docker.hcl
targets: ${{ inputs.targets }}
source: .
set: |
*.cache-from=type=gha,ignore-error=true,scope=${{ steps.docker_cache_key.outputs.replaced }}
*.cache-to=type=gha,mode=max,ignore-error=true,scope=${{ steps.docker_cache_key.outputs.replaced }}
Expand Down Expand Up @@ -212,7 +213,7 @@ jobs:
fetch-depth: 2

- name: configure docker buildx
uses: docker/setup-buildx-action@v3.7.1
uses: docker/setup-buildx-action@v3.8.0

- name: login to docker registry
if: ${{ inputs.dockerize }}
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/dockerize-cli.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
- name: build docker images
timeout-minutes: 360
id: docker-bake
uses: docker/bake-action@v5
uses: docker/bake-action@v6.0.0
env:
DOCKER_REGISTRY: ${{ inputs.registry }}/${{ inputs.imageName }}/
COMMIT_SHA: ${{ inputs.cliVersion }}
Expand All @@ -74,5 +74,6 @@ jobs:
push: true
files: docker/docker.hcl
targets: cli
source: .
set: |
${{ steps.docker-bake-inputs.outputs.set }}
2 changes: 1 addition & 1 deletion .github/workflows/tests-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jobs:
-f docker/docker-compose.end2end.yml \
logs
- uses: actions/upload-artifact@v4.4.3
- uses: actions/upload-artifact@v4.5.0
if: ${{ failure() }}
with:
name: cypress
Expand Down
2 changes: 1 addition & 1 deletion .node-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
22.12
22.13
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
22.12
22.13
8 changes: 4 additions & 4 deletions configs/cargo/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

248 changes: 248 additions & 0 deletions cypress/e2e/laboratory-collections.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
import { laboratory } from '../support/testkit';

beforeEach(() => {
cy.clearAllLocalStorage().then(() => {
return cy.task('seedTarget').then(({ slug, refreshToken }: any) => {
cy.setCookie('sRefreshToken', refreshToken);

cy.visit(`/${slug}/laboratory`);

// To make sure the operation collections tab is opened
// It first opens the Documentation Explorer or GraphiQL Explorer,
// then opens the Operation Collections tab.
// It does that, because the Operation Collections tab could be already opened for some reason.
// This way it's guaranteed that the Operation Collections tab is opened.
cy.get('[aria-label*="Show Documentation Explorer"], [aria-label*="Show GraphiQL Explorer"]')
.first()
.click();
cy.get('[aria-label="Show Operation Collections"]').click();
});
});
});

const collections = {
/**
* Opens the modal to create a new collection and fills the form
*/
create(args: { name: string; description: string }) {
cy.get('button[data-cy="new-collection"]').click();
cy.get('div[data-cy="create-collection-modal"] input[name="name"]').type(args.name);
cy.get('div[data-cy="create-collection-modal"] input[name="description"]').type(
args.description,
);
cy.get('div[data-cy="create-collection-modal"] button[type="submit"]').click();
},
/**
* Clicks on a collection in the sidebar
*/
clickCollectionButton(name: string) {
cy.get('button[data-cy="collection-item-trigger"]').contains(name).click();
},
/**
* Saves the current operation as a new operation and assigns it to a collection
*/
saveCurrentOperationAs(args: { name: string; collectionName: string }) {
cy.get('[data-cy="save-operation"]').click();
cy.get('[data-cy="save-operation-as"]').click();

cy.get('div[data-cy="create-operation-modal"] input[name="name"]').type(args.name);
cy.get(
'div[data-cy="create-operation-modal"] button[data-cy="collection-select-trigger"]',
).click();

cy.get('div[data-cy="collection-select-item"]').contains(args.collectionName).click();
cy.get('div[data-cy="create-operation-modal"] button[type="submit"]').click();
},
/**
* Opens the menu for a specific operation, to access delete, copy link or edit buttons.
*/
openOperationMenu(name: string) {
return cy.get(`a[data-cy="operation-${name}"] ~ button`).click();
},
/**
* Opens the menu for a specific collection, to access delete or edit buttons.
*/
openCollectionMenu(name: string) {
return cy
.contains(`[data-cy="collection-item-trigger"]`, name)
.parent()
.get('[data-cy="collection-menu-trigger"]')
.click();
},
/**
* Returns the operation element
*/
getOperationButton(name: string) {
return cy.get<HTMLAnchorElement>(`a[data-cy="operation-${name}"]`);
},
/**
* Returns the collection element
*/
getCollectionButton(name: string) {
return cy.contains('[data-cy="collection-item"]', name);
},
};

describe('Laboratory > Collections', () => {
it('create a collection and an operation', () => {
collections.create({
name: 'collection-1',
description: 'Description 1',
});
laboratory.updateEditorValue(`query op1 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-1',
collectionName: 'collection-1',
});
collections.getOperationButton('operation-1').should('exist');
});

it(`edit collection's name`, () => {
collections.create({
name: 'collection-1',
description: 'Description 1',
});
laboratory.updateEditorValue(`query op1 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-1',
collectionName: 'collection-1',
});

collections.openCollectionMenu('collection-1');
// Click on the edit button and fill the form
cy.get('[data-cy="edit-collection"]').click();
cy.get('[data-cy="create-collection-modal"]').should('exist');
cy.get('[data-cy="create-collection-modal"] input[name="name"]')
.clear()
.type('collection-1-updated');
cy.get('[data-cy="create-collection-modal"] button[data-cy="confirm"]').click();

collections.getCollectionButton('collection-1-updated').should('exist');
collections.getOperationButton('operation-1').should('exist');
});

it('delete a collection', () => {
collections.create({
name: 'collection-1',
description: 'Description 1',
});
laboratory.updateEditorValue(`query op1 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-1',
collectionName: 'collection-1',
});

collections.getOperationButton('operation-1').should('exist');
collections.getCollectionButton('collection-1').should('exist');

collections.openCollectionMenu('collection-1');
// Click on the delete button and confirm the deletion
cy.get('[data-cy="delete-collection"]').click();
cy.get('[data-cy="delete-collection-modal"]').should('exist');
cy.get('[data-cy="delete-collection-modal"] button[data-cy="confirm"]').click();

collections.getOperationButton('operation-1').should('not.exist');
collections.getCollectionButton('collection-1').should('not.exist');
});

it(`edit operation's name`, () => {
collections.create({
name: 'collection-1',
description: 'Description 1',
});
laboratory.updateEditorValue(`query op1 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-1',
collectionName: 'collection-1',
});

collections.openOperationMenu('operation-1');
// Click on the edit button and fill the form
cy.get('[data-cy="edit-operation"]').click();
cy.get('[data-cy="edit-operation-modal"]').should('exist');
cy.get('[data-cy="edit-operation-modal"] input[name="name"]').type('operation-1-updated');
cy.get('[data-cy="edit-operation-modal"] button[data-cy="confirm"]').click();

collections.getOperationButton('operation-1').should('not.exist');
collections.getOperationButton('operation-1-updated').should('exist');
});

it('delete an operation', () => {
collections.create({
name: 'collection-1',
description: 'Description 1',
});
laboratory.updateEditorValue(`query op1 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-1',
collectionName: 'collection-1',
});

laboratory.openNewTab();
laboratory.updateEditorValue(`query op2 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-2',
collectionName: 'collection-1',
});

collections.openOperationMenu('operation-1');
// Click on the delete button and confirm the deletion
cy.get('[data-cy="delete-operation"]').click();
cy.get('[data-cy="delete-operation-modal"]').should('exist');
cy.get('[data-cy="delete-operation-modal"] button[data-cy="confirm"]').click();

collections.getOperationButton('operation-1').should('not.exist');
collections.getOperationButton('operation-2').should('exist');
});

it('visiting a copied operation link should open the operation', () => {
collections.create({
name: 'collection-1',
description: 'Description 1',
});
collections.create({
name: 'collection-2',
description: 'Description 2',
});
collections.clickCollectionButton('collection-1');
laboratory.updateEditorValue(`query op1 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-1',
collectionName: 'collection-1',
});

laboratory.openNewTab();
laboratory.updateEditorValue(`query op2 { test }`);
collections.saveCurrentOperationAs({
name: 'operation-2',
collectionName: 'collection-2',
});

collections.openOperationMenu('operation-1');

// Stub the clipboard API to intercept the copied URL
cy.window().then(win => {
cy.stub(win.navigator.clipboard, 'writeText').as('copied');
});

cy.get('[data-cy="copy-operation-link"]').click();

cy.get<{
getCall(index: number): {
args: unknown[];
};
}>('@copied')
.should('have.been.calledOnce')
.then(stub => {
const copiedUrl = stub.getCall(0).args[0]; // Extract the copied URL
if (typeof copiedUrl !== 'string') {
throw new Error('The copied URL is not a string');
}
// Navigate to the copied URL
return cy.visit(copiedUrl);
});

laboratory.assertActiveTab('operation-1');
laboratory.getEditorValue().should('contain', 'op1');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function setEditorScript(script: string) {
setMonacoEditorContents('preflight-script-editor', script);
}

describe('Preflight Script', () => {
describe('Laboratory > Preflight Script', () => {
it('mini script editor is read only', () => {
cy.dataCy('toggle-preflight-script').click();
// Wait loading disappears
Expand Down
Loading

0 comments on commit 0a00cc9

Please sign in to comment.