2
0

feat(integration): Add Google Sheets integration

This commit is contained in:
Baptiste Arnaud
2022-01-18 18:25:18 +01:00
parent 2814a352b2
commit f49b5143cf
67 changed files with 2560 additions and 391 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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' }],

View File

@ -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,
},
},

View 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()
}