diff --git a/.husky/post-checkout b/.husky/post-checkout new file mode 100755 index 000000000..5abf8ed93 --- /dev/null +++ b/.husky/post-checkout @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { printf >&2 "\n%s\n\n" "This repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'post-checkout' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks')."; exit 2; } +git lfs post-checkout "$@" diff --git a/.husky/post-commit b/.husky/post-commit new file mode 100755 index 000000000..b8b76c2c4 --- /dev/null +++ b/.husky/post-commit @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { printf >&2 "\n%s\n\n" "This repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'post-commit' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks')."; exit 2; } +git lfs post-commit "$@" diff --git a/.husky/post-merge b/.husky/post-merge new file mode 100755 index 000000000..726f90989 --- /dev/null +++ b/.husky/post-merge @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { printf >&2 "\n%s\n\n" "This repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'post-merge' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks')."; exit 2; } +git lfs post-merge "$@" diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 000000000..5f26dc455 --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { printf >&2 "\n%s\n\n" "This repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'pre-push' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks')."; exit 2; } +git lfs pre-push "$@" diff --git a/README_PR.md b/README_PR.md new file mode 100644 index 000000000..86ea629e7 --- /dev/null +++ b/README_PR.md @@ -0,0 +1,20 @@ +## ✅ PR: Add Cypress test with mock Stakwork endpoints for Hivechat Chat Mode + +**Summary:** +- Adds fixture file with mock Stakwork responses +- Adds Cypress command to intercept and mock `/hivechat/response` and webhook endpoints +- New e2e test covering text, code & screen artifacts, and action dialogs +- Configurable mock/real endpoints via `useMocks` + +**Why:** Enable consistent backend-independent tests. +Resolves part of https://github.com/stakwork/sphinx-tribes-frontend/pull/1395 + +**How to run:** +```bash +yarn cy:open # UI mode +yarn cy:run # headless +``` + +Toggle mock/real: edit `cypress.config.js` → `env.useMocks` + +Ready for review 🚀 diff --git a/cypress.config.js b/cypress.config.js new file mode 100644 index 000000000..fb4a07b4e --- /dev/null +++ b/cypress.config.js @@ -0,0 +1,10 @@ +const { defineConfig } = require("cypress"); + +module.exports = defineConfig({ + e2e: { + baseUrl: 'http://localhost:3007', + env: { + useMocks: true + } + } +}); \ No newline at end of file diff --git a/cypress/e2e/hivechat_flow.cy.js b/cypress/e2e/hivechat_flow.cy.js new file mode 100644 index 000000000..4cbbccd3c --- /dev/null +++ b/cypress/e2e/hivechat_flow.cy.js @@ -0,0 +1,42 @@ +describe('Hivechat Flow with Mock Stakwork API', () => { + beforeEach(() => { + cy.mockStakworkAPI(); + cy.login('testuser'); // use your login helper + cy.visit('/workspace/123/hivechat/456'); + cy.wait(1000); + }); + + it('Completes hivechat flow', () => { + cy.get('[data-testid="chat-mode-button"]').click(); + cy.get('[data-testid="message-input"]').type('Lets create a new @ticket'); + cy.get('[data-testid="send-message-button"]').click(); + + cy.wait('@hivechatResponse'); + cy.get('[data-testid="artifact-tab-Text"]').should('be.visible'); + cy.get('[data-testid="artifact-content-text"]').should('contain', 'Market Research'); + + cy.get('[data-testid="message-input"]').clear().type('Yes sounds good'); + cy.get('[data-testid="send-message-button"]').click(); + + cy.wait('@hivechatResponse'); + cy.get('[data-testid="artifact-tab-Code"]').should('be.visible').click(); + cy.get('[data-testid="artifact-content-code"]').should('contain', 'LeaderboardPage'); + + cy.get('[data-testid="artifact-tab-Screen"]').click(); + cy.get('[data-testid="artifact-content-screen"]').should('be.visible'); + + cy.get('[data-testid="action-dialog"]').contains('Yes').click(); + + cy.wait('@hivechatResponse'); + cy.get('[data-testid="artifact-content-code"]').should('contain', 'applyPatch'); + + cy.get('[data-testid="action-dialog"]').contains('Yes').click(); + + cy.wait('@hivechatResponse'); + cy.get('[data-testid="message-history"]').should('contain', 'Patch applied successfully'); + }); + + afterEach(() => { + cy.logout(); + }); +}); \ No newline at end of file diff --git a/cypress/fixtures/stakwork-responses.js b/cypress/fixtures/stakwork-responses.js new file mode 100644 index 000000000..b5c2b1e6c --- /dev/null +++ b/cypress/fixtures/stakwork-responses.js @@ -0,0 +1,133 @@ +export const stakworkResponses = { + initialResponse: { + value: { + chatId: "cvljgu7paij1jhtehg9g", + messageId: "cvljh5npaij1jhtehga0", + response: "Ok here's the plan for you to review...", + sourceWebsocketId: "52a3e86e-d466-40a4-a4a8-e88938653335", + artifacts: [ + { + id: "111-222-333-444", + type: "action", + content: { + actionText: "", + options: [ + { + action_type: "chat", + option_label: "Give me feedback", + option_response: "textbox", + webhook: "https://jobs.stakwork.com/customer_webhooks/v1?..." + } + ] + } + }, + { + id: "550e8400-e29b-41d4-a716-446655440123", + messageId: "msg_123456", + type: "text", + content: { + text_type: "markdown", + content: "Creating a plan for market domination..." + } + } + ] + } + }, + codeScreenResponse: { + value: { + chatId: "cvljgu7paij1jhtehg9g", + messageId: "cvljh5npaij1jhtehga0", + response: "Alright I've implemented the code below...", + sourceWebsocketId: "52a3e86e-d466-40a4-a4a8-e88938653335", + artifacts: [ + { + id: "111-222-333-444", + type: "action", + content: { + actionText: "I detected an error do you want to see the logs?", + options: [ + { + action_type: "chat", + option_label: "Give me feedback", + option_response: "textbox", + webhook: "https://jobs.stakwork.com/customer_webhooks/v1?..." + }, + { + action_type: "button", + option_label: "Yes", + option_response: "Yes", + webhook: "https://jobs.stakwork.com/customer_webhooks/v1?..." + } + ] + } + }, + { + id: "550e8400-e29b-41d4-a716-446655440001", + messageId: "msg_123456", + type: "visual", + content: { + visual_type: "screen", + url: "https://community.sphinx.chat/leaderboard" + } + }, + { + id: "550e8400-e29b-41d4-a716-446655440123", + messageId: "msg_123456", + type: "text", + content: { + text_type: "code", + content: "import React, { useState } from 'react';..." + } + } + ] + } + }, + logsResponse: { + value: { + chatId: "cvljgu7paij1jhtehg9g", + messageId: "cvljh5npaij1jhtehga0", + response: "OK here's the logs, they should be streaming through now...", + sourceWebsocketId: "52a3e86e-d466-40a4-a4a8-e88938653335", + artifacts: [ + { + id: "111-222-333-444", + type: "action", + content: { + actionText: "how about we fix this with patch 1523.patch", + options: [ + { + action_type: "chat", + option_label: "Give me feedback", + option_response: "textbox", + webhook: "https://jobs.stakwork.com/customer_webhooks/v1?..." + }, + { + action_type: "button", + option_label: "Yes", + option_response: "Yes", + webhook: "https://jobs.stakwork.com/customer_webhooks/v1?..." + } + ] + } + }, + { + id: "550e8400-e29b-41d4-a716-446655440123", + messageId: "msg_123456", + type: "text", + content: { + text_type: "code", + language: "typescript", + content: "function applyPatch(...) { ... }" + } + } + ] + } + }, + finalResponse: { + value: { + chatId: "cvljgu7paij1jhtehg9g", + messageId: "cvljh5npaij1jhtehga0", + response: "Patch applied successfully! The fix has been deployed." + } + } +}; \ No newline at end of file diff --git a/cypress/support/commands.js b/cypress/support/commands.js new file mode 100644 index 000000000..fe233d59e --- /dev/null +++ b/cypress/support/commands.js @@ -0,0 +1,21 @@ +import { stakworkResponses } from '../fixtures/stakwork-responses'; + +Cypress.Commands.add('mockStakworkAPI', () => { + if (Cypress.env('useMocks') === false) return; + + let responseCounter = 0; + + cy.intercept('POST', '**/hivechat/response', (req) => { + let res = stakworkResponses.finalResponse; + if (responseCounter === 0) res = stakworkResponses.initialResponse; + else if (responseCounter === 1) res = stakworkResponses.codeScreenResponse; + else if (responseCounter === 2) res = stakworkResponses.logsResponse; + responseCounter++; + req.reply({ statusCode: 200, body: res }); + }).as('hivechatResponse'); + + cy.intercept('POST', '**/customer_webhooks/**', { + statusCode: 200, + body: { success: true } + }).as('webhookAction'); +}); \ No newline at end of file