feat(integration): ✨ Add Google Sheets integration
This commit is contained in:
@ -0,0 +1,80 @@
|
||||
{
|
||||
"id": "typebot4",
|
||||
"createdAt": "2022-01-17T14:37:01.826Z",
|
||||
"updatedAt": "2022-01-17T14:37:01.826Z",
|
||||
"name": "My typebot",
|
||||
"ownerId": "user2",
|
||||
"publishedTypebotId": null,
|
||||
"folderId": null,
|
||||
"blocks": {
|
||||
"byId": {
|
||||
"bec5A5bLwenmZpCJc8FRaM": {
|
||||
"id": "bec5A5bLwenmZpCJc8FRaM",
|
||||
"title": "Start",
|
||||
"stepIds": ["uDMB7a2ucg17WGvbQJjeRn"],
|
||||
"graphCoordinates": { "x": 0, "y": 0 }
|
||||
},
|
||||
"bcyiT7P6E99YnHKnpxs4Yux": {
|
||||
"id": "bcyiT7P6E99YnHKnpxs4Yux",
|
||||
"title": "Block #2",
|
||||
"stepIds": ["step1"],
|
||||
"graphCoordinates": { "x": 411, "y": 108 }
|
||||
},
|
||||
"bgpNxHtBBXWrP1QMe2A8hZ9": {
|
||||
"id": "bgpNxHtBBXWrP1QMe2A8hZ9",
|
||||
"title": "Block #3",
|
||||
"graphCoordinates": { "x": 1, "y": 236 },
|
||||
"stepIds": ["sj72oDhJEe4N92KTt64GKWs"]
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"bec5A5bLwenmZpCJc8FRaM",
|
||||
"bcyiT7P6E99YnHKnpxs4Yux",
|
||||
"bgpNxHtBBXWrP1QMe2A8hZ9"
|
||||
]
|
||||
},
|
||||
"steps": {
|
||||
"byId": {
|
||||
"step1": {
|
||||
"id": "step1",
|
||||
"type": "Google Sheets",
|
||||
"blockId": "bcyiT7P6E99YnHKnpxs4Yux"
|
||||
},
|
||||
"uDMB7a2ucg17WGvbQJjeRn": {
|
||||
"id": "uDMB7a2ucg17WGvbQJjeRn",
|
||||
"type": "start",
|
||||
"label": "Start",
|
||||
"target": { "blockId": "bgpNxHtBBXWrP1QMe2A8hZ9" },
|
||||
"blockId": "bec5A5bLwenmZpCJc8FRaM"
|
||||
},
|
||||
"sj72oDhJEe4N92KTt64GKWs": {
|
||||
"id": "sj72oDhJEe4N92KTt64GKWs",
|
||||
"blockId": "bgpNxHtBBXWrP1QMe2A8hZ9",
|
||||
"type": "email input",
|
||||
"target": { "blockId": "bcyiT7P6E99YnHKnpxs4Yux" },
|
||||
"options": { "variableId": "8H3aQsNji2Gyfpp3RPozNN" }
|
||||
}
|
||||
},
|
||||
"allIds": ["uDMB7a2ucg17WGvbQJjeRn", "step1", "sj72oDhJEe4N92KTt64GKWs"]
|
||||
},
|
||||
"choiceItems": { "byId": {}, "allIds": [] },
|
||||
"variables": {
|
||||
"byId": {
|
||||
"8H3aQsNji2Gyfpp3RPozNN": {
|
||||
"id": "8H3aQsNji2Gyfpp3RPozNN",
|
||||
"name": "Email"
|
||||
}
|
||||
},
|
||||
"allIds": ["8H3aQsNji2Gyfpp3RPozNN"]
|
||||
},
|
||||
"theme": {
|
||||
"general": {
|
||||
"font": "Open Sans",
|
||||
"background": { "type": "None", "content": "#ffffff" }
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 }
|
||||
},
|
||||
"publicId": null
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
{
|
||||
"id": "typebot4",
|
||||
"createdAt": "2022-01-17T14:37:01.826Z",
|
||||
"updatedAt": "2022-01-17T14:37:01.826Z",
|
||||
"name": "My typebot",
|
||||
"ownerId": "user2",
|
||||
"publishedTypebotId": null,
|
||||
"folderId": null,
|
||||
"blocks": {
|
||||
"byId": {
|
||||
"bec5A5bLwenmZpCJc8FRaM": {
|
||||
"id": "bec5A5bLwenmZpCJc8FRaM",
|
||||
"title": "Start",
|
||||
"stepIds": ["uDMB7a2ucg17WGvbQJjeRn"],
|
||||
"graphCoordinates": { "x": 0, "y": 0 }
|
||||
},
|
||||
"bcyiT7P6E99YnHKnpxs4Yux": {
|
||||
"id": "bcyiT7P6E99YnHKnpxs4Yux",
|
||||
"title": "Block #2",
|
||||
"stepIds": ["step1"],
|
||||
"graphCoordinates": { "x": 411, "y": 108 }
|
||||
},
|
||||
"bgpNxHtBBXWrP1QMe2A8hZ9": {
|
||||
"id": "bgpNxHtBBXWrP1QMe2A8hZ9",
|
||||
"title": "Block #3",
|
||||
"stepIds": ["sj72oDhJEe4N92KTt64GKWs"],
|
||||
"graphCoordinates": { "x": 1, "y": 236 }
|
||||
},
|
||||
"buwMV9tx2EFcMbRkNTELt3J": {
|
||||
"id": "buwMV9tx2EFcMbRkNTELt3J",
|
||||
"title": "Block #4",
|
||||
"graphCoordinates": { "x": 441, "y": 330 },
|
||||
"stepIds": ["s2R2bk7qfSRVgTyRmPhVw7p"]
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"bec5A5bLwenmZpCJc8FRaM",
|
||||
"bcyiT7P6E99YnHKnpxs4Yux",
|
||||
"bgpNxHtBBXWrP1QMe2A8hZ9",
|
||||
"buwMV9tx2EFcMbRkNTELt3J"
|
||||
]
|
||||
},
|
||||
"steps": {
|
||||
"byId": {
|
||||
"step1": {
|
||||
"id": "step1",
|
||||
"type": "Google Sheets",
|
||||
"blockId": "bcyiT7P6E99YnHKnpxs4Yux",
|
||||
"target": { "blockId": "buwMV9tx2EFcMbRkNTELt3J" }
|
||||
},
|
||||
"uDMB7a2ucg17WGvbQJjeRn": {
|
||||
"id": "uDMB7a2ucg17WGvbQJjeRn",
|
||||
"type": "start",
|
||||
"label": "Start",
|
||||
"target": { "blockId": "bgpNxHtBBXWrP1QMe2A8hZ9" },
|
||||
"blockId": "bec5A5bLwenmZpCJc8FRaM"
|
||||
},
|
||||
"sj72oDhJEe4N92KTt64GKWs": {
|
||||
"id": "sj72oDhJEe4N92KTt64GKWs",
|
||||
"type": "email input",
|
||||
"target": { "blockId": "bcyiT7P6E99YnHKnpxs4Yux" },
|
||||
"blockId": "bgpNxHtBBXWrP1QMe2A8hZ9",
|
||||
"options": { "variableId": "8H3aQsNji2Gyfpp3RPozNN" }
|
||||
},
|
||||
"s2R2bk7qfSRVgTyRmPhVw7p": {
|
||||
"id": "s2R2bk7qfSRVgTyRmPhVw7p",
|
||||
"blockId": "buwMV9tx2EFcMbRkNTELt3J",
|
||||
"type": "text",
|
||||
"content": {
|
||||
"html": "<div>Your name is: {{First name}} {{Last name}}</div>",
|
||||
"richText": [
|
||||
{
|
||||
"type": "p",
|
||||
"children": [
|
||||
{ "text": "Your name is: {{First name}} {{Last name}}" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"plainText": "Your name is: {{First name}} {{Last name}}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"uDMB7a2ucg17WGvbQJjeRn",
|
||||
"step1",
|
||||
"sj72oDhJEe4N92KTt64GKWs",
|
||||
"s2R2bk7qfSRVgTyRmPhVw7p"
|
||||
]
|
||||
},
|
||||
"choiceItems": { "byId": {}, "allIds": [] },
|
||||
"variables": {
|
||||
"byId": {
|
||||
"8H3aQsNji2Gyfpp3RPozNN": {
|
||||
"id": "8H3aQsNji2Gyfpp3RPozNN",
|
||||
"name": "Email"
|
||||
}
|
||||
},
|
||||
"allIds": ["8H3aQsNji2Gyfpp3RPozNN"]
|
||||
},
|
||||
"theme": {
|
||||
"general": {
|
||||
"font": "Open Sans",
|
||||
"background": { "type": "None", "content": "#ffffff" }
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 }
|
||||
},
|
||||
"publicId": null
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { InputStepType, PublicTypebot, Typebot } from 'models'
|
||||
import { Plan, PrismaClient } from 'db'
|
||||
import { CredentialsType, Plan, PrismaClient } from 'db'
|
||||
import { parseTestTypebot } from './utils'
|
||||
import { userIds } from './data'
|
||||
|
||||
@ -7,9 +7,10 @@ const prisma = new PrismaClient()
|
||||
|
||||
const teardownTestData = async () => prisma.user.deleteMany()
|
||||
|
||||
export const seedDb = async () => {
|
||||
export const seedDb = async (googleRefreshToken: string) => {
|
||||
await teardownTestData()
|
||||
await createUsers()
|
||||
await createCredentials(googleRefreshToken)
|
||||
await createFolders()
|
||||
await createTypebots()
|
||||
await createResults()
|
||||
@ -33,6 +34,23 @@ const createUsers = () =>
|
||||
],
|
||||
})
|
||||
|
||||
const createCredentials = (refresh_token: string) =>
|
||||
prisma.credentials.createMany({
|
||||
data: [
|
||||
{
|
||||
name: 'test2@gmail.com',
|
||||
ownerId: userIds[1],
|
||||
type: CredentialsType.GOOGLE_SHEETS,
|
||||
data: {
|
||||
expiry_date: 1642441058842,
|
||||
access_token:
|
||||
'ya29.A0ARrdaM--PV_87ebjywDJpXKb77NBFJl16meVUapYdfNv6W6ZzqqC47fNaPaRjbDbOIIcp6f49cMaX5ndK9TAFnKwlVqz3nrK9nLKqgyDIhYsIq47smcAIZkK56SWPx3X3DwAFqRu2UPojpd2upWwo-3uJrod',
|
||||
refresh_token,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const createFolders = () =>
|
||||
prisma.dashboardFolder.createMany({
|
||||
data: [{ ownerId: userIds[1], name: 'Folder #1', id: 'folder1' }],
|
||||
|
@ -280,7 +280,9 @@ const createTypebotWithStep = (step: Omit<InputStep, 'id' | 'blockId'>) => {
|
||||
//@ts-ignore
|
||||
options:
|
||||
step.type === InputStepType.CHOICE
|
||||
? { itemIds: ['item1'] }
|
||||
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
//@ts-ignore
|
||||
{ itemIds: ['item1'] }
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
|
139
apps/builder/cypress/tests/integrations.ts
Normal file
139
apps/builder/cypress/tests/integrations.ts
Normal file
@ -0,0 +1,139 @@
|
||||
import { preventUserFromRefreshing } from 'cypress/plugins/utils'
|
||||
import { getIframeBody } from 'cypress/support'
|
||||
|
||||
describe('Google sheets', () => {
|
||||
beforeEach(() => {
|
||||
cy.task('seed', Cypress.env('GOOGLE_SHEETS_REFRESH_TOKEN'))
|
||||
cy.signOut()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
cy.window().then((win) => {
|
||||
win.removeEventListener('beforeunload', preventUserFromRefreshing)
|
||||
})
|
||||
})
|
||||
|
||||
it('Insert row should work', () => {
|
||||
cy.intercept({
|
||||
url: '/api/integrations/google-sheets/spreadsheets/1k_pIDw3YHl9tlZusbBVSBRY0PeRPd2H6t4Nj7rwnOtM/sheets/0',
|
||||
method: 'POST',
|
||||
}).as('insertRowInGoogleSheets')
|
||||
cy.loadTypebotFixtureInDatabase('typebots/integrations/googleSheets.json')
|
||||
cy.signIn('test2@gmail.com')
|
||||
cy.visit('/typebots/typebot4/edit')
|
||||
|
||||
fillInSpreadsheetInfo()
|
||||
|
||||
cy.findByRole('button', { name: 'Select an operation' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Insert a row' }).click({ force: true })
|
||||
|
||||
cy.findByRole('button', { name: 'Select a column' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Email' }).click()
|
||||
cy.findByRole('button', { name: 'Insert a variable' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Email' }).click()
|
||||
|
||||
cy.findByRole('button', { name: 'Add' }).click()
|
||||
|
||||
cy.findByRole('button', { name: 'Select a column' }).click()
|
||||
cy.findByRole('menuitem', { name: 'First name' }).click()
|
||||
cy.findAllByPlaceholderText('Type a value...').last().type('Georges')
|
||||
|
||||
cy.findByRole('button', { name: 'Preview' }).click()
|
||||
getIframeBody()
|
||||
.findByPlaceholderText('Type your email...')
|
||||
.type('georges@gmail.com{enter}')
|
||||
cy.wait('@insertRowInGoogleSheets')
|
||||
.then((interception) => {
|
||||
return interception.response?.statusCode
|
||||
})
|
||||
.should('eq', 200)
|
||||
})
|
||||
|
||||
it('Update row should work', () => {
|
||||
cy.intercept({
|
||||
url: '/api/integrations/google-sheets/spreadsheets/1k_pIDw3YHl9tlZusbBVSBRY0PeRPd2H6t4Nj7rwnOtM/sheets/0',
|
||||
method: 'PATCH',
|
||||
}).as('updateRowInGoogleSheets')
|
||||
cy.loadTypebotFixtureInDatabase('typebots/integrations/googleSheets.json')
|
||||
cy.signIn('test2@gmail.com')
|
||||
cy.visit('/typebots/typebot4/edit')
|
||||
|
||||
fillInSpreadsheetInfo()
|
||||
|
||||
cy.findByRole('button', { name: 'Select an operation' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Update a row' }).click({ force: true })
|
||||
|
||||
cy.findAllByRole('button', { name: 'Select a column' }).first().click()
|
||||
cy.findByRole('menuitem', { name: 'Email' }).click()
|
||||
cy.findAllByRole('button', { name: 'Insert a variable' }).first().click()
|
||||
cy.findByRole('menuitem', { name: 'Email' }).click()
|
||||
|
||||
cy.findByRole('button', { name: 'Select a column' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Last name' }).click()
|
||||
cy.findAllByPlaceholderText('Type a value...').last().type('Last name')
|
||||
|
||||
cy.findByRole('button', { name: 'Preview' }).click()
|
||||
getIframeBody()
|
||||
.findByPlaceholderText('Type your email...')
|
||||
.type('test@test.com{enter}')
|
||||
cy.wait('@updateRowInGoogleSheets')
|
||||
.then((interception) => {
|
||||
return interception.response?.statusCode
|
||||
})
|
||||
.should('eq', 200)
|
||||
})
|
||||
|
||||
it('Get row should work', () => {
|
||||
cy.loadTypebotFixtureInDatabase(
|
||||
'typebots/integrations/googleSheetsGet.json'
|
||||
)
|
||||
cy.signIn('test2@gmail.com')
|
||||
cy.visit('/typebots/typebot4/edit')
|
||||
|
||||
fillInSpreadsheetInfo()
|
||||
|
||||
cy.findByRole('button', { name: 'Select an operation' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Get data from sheet' }).click({
|
||||
force: true,
|
||||
})
|
||||
|
||||
cy.findAllByRole('button', { name: 'Select a column' }).first().click()
|
||||
cy.findByRole('menuitem', { name: 'Email' }).click()
|
||||
cy.findByRole('button', { name: 'Insert a variable' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Email' }).click()
|
||||
|
||||
cy.findByRole('button', { name: 'Select a column' }).click()
|
||||
cy.findByRole('menuitem', { name: 'First name' }).click()
|
||||
createNewVar('First name')
|
||||
|
||||
cy.findByRole('button', { name: 'Add' }).click()
|
||||
|
||||
cy.findByRole('button', { name: 'Select a column' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Last name' }).click()
|
||||
createNewVar('Last name')
|
||||
|
||||
cy.findByRole('button', { name: 'Preview' }).click()
|
||||
getIframeBody()
|
||||
.findByPlaceholderText('Type your email...')
|
||||
.type('test2@test.com{enter}')
|
||||
getIframeBody().findByText('Your name is: John Smith').should('exist')
|
||||
})
|
||||
})
|
||||
|
||||
const fillInSpreadsheetInfo = () => {
|
||||
cy.findByTestId('step-step1').click()
|
||||
|
||||
cy.findByRole('button', { name: 'Select an account' }).click()
|
||||
cy.findByRole('menuitem', { name: 'test2@gmail.com' }).click()
|
||||
|
||||
cy.findByPlaceholderText('Search for spreadsheet').type('CR')
|
||||
cy.findByRole('menuitem', { name: 'CRM' }).click()
|
||||
|
||||
cy.findByPlaceholderText('Select the sheet').type('Sh')
|
||||
cy.findByRole('menuitem', { name: 'Sheet1' }).click()
|
||||
}
|
||||
|
||||
const createNewVar = (name: string) => {
|
||||
cy.findAllByTestId('variables-input').last().type(name)
|
||||
cy.findByRole('menuitem', { name: `Create "${name}"` }).click()
|
||||
}
|
Reference in New Issue
Block a user