perf(e2e): ⚡️ Migrate to Playwright
BIN
apps/builder/playwright/fixtures/avatar.jpg
Normal file
After Width: | Height: | Size: 29 KiB |
@ -0,0 +1,117 @@
|
||||
{
|
||||
"id": "ckylszb9z0354z31a623dg7ji",
|
||||
"createdAt": "2022-01-19T17:12:27.863Z",
|
||||
"updatedAt": "2022-01-19T17:12:27.863Z",
|
||||
"name": "My typebot",
|
||||
"ownerId": "ckylsz8yy0335z31amvq0jwtt",
|
||||
"publishedTypebotId": null,
|
||||
"folderId": null,
|
||||
"webhooks": { "byId": {}, "allIds": [] },
|
||||
"blocks": {
|
||||
"byId": {
|
||||
"j24wz82YG3rjXMgrmCiTLy": {
|
||||
"id": "j24wz82YG3rjXMgrmCiTLy",
|
||||
"title": "Start",
|
||||
"stepIds": ["1NdXPCiRicqDA8k4JfnXfi"],
|
||||
"graphCoordinates": { "x": 0, "y": 0 }
|
||||
},
|
||||
"bmaKTUXkT2cc3wtKfK7ra71": {
|
||||
"id": "bmaKTUXkT2cc3wtKfK7ra71",
|
||||
"title": "Block #2",
|
||||
"graphCoordinates": { "x": 175, "y": 197 },
|
||||
"stepIds": ["spHxPWbSqkVZW9gqH86ovC5"]
|
||||
},
|
||||
"bnt8fM5Wgc8gBg2iSmUcfJu": {
|
||||
"id": "bnt8fM5Wgc8gBg2iSmUcfJu",
|
||||
"title": "Block #3",
|
||||
"graphCoordinates": { "x": 504, "y": 347 },
|
||||
"stepIds": ["siPoEE9H27hVHqykth3a7Kj"]
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"j24wz82YG3rjXMgrmCiTLy",
|
||||
"bmaKTUXkT2cc3wtKfK7ra71",
|
||||
"bnt8fM5Wgc8gBg2iSmUcfJu"
|
||||
]
|
||||
},
|
||||
"steps": {
|
||||
"byId": {
|
||||
"1NdXPCiRicqDA8k4JfnXfi": {
|
||||
"id": "1NdXPCiRicqDA8k4JfnXfi",
|
||||
"type": "start",
|
||||
"label": "Start",
|
||||
"blockId": "j24wz82YG3rjXMgrmCiTLy",
|
||||
"edgeId": "benDCcLMUWNvi6Fg6CXE9H"
|
||||
},
|
||||
"spHxPWbSqkVZW9gqH86ovC5": {
|
||||
"id": "spHxPWbSqkVZW9gqH86ovC5",
|
||||
"blockId": "bmaKTUXkT2cc3wtKfK7ra71",
|
||||
"type": "email input",
|
||||
"options": { "variableId": "oexLr4sJQNVdSnYCGgGRB3" },
|
||||
"edgeId": "6Tax9rw7L8kmRn9JRD2Mrg"
|
||||
},
|
||||
"siPoEE9H27hVHqykth3a7Kj": {
|
||||
"id": "siPoEE9H27hVHqykth3a7Kj",
|
||||
"blockId": "bnt8fM5Wgc8gBg2iSmUcfJu",
|
||||
"type": "Google Sheets"
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"1NdXPCiRicqDA8k4JfnXfi",
|
||||
"spHxPWbSqkVZW9gqH86ovC5",
|
||||
"siPoEE9H27hVHqykth3a7Kj"
|
||||
]
|
||||
},
|
||||
"choiceItems": { "byId": {}, "allIds": [] },
|
||||
"variables": {
|
||||
"byId": {
|
||||
"oexLr4sJQNVdSnYCGgGRB3": {
|
||||
"id": "oexLr4sJQNVdSnYCGgGRB3",
|
||||
"name": "Email"
|
||||
}
|
||||
},
|
||||
"allIds": ["oexLr4sJQNVdSnYCGgGRB3"]
|
||||
},
|
||||
"edges": {
|
||||
"byId": {
|
||||
"benDCcLMUWNvi6Fg6CXE9H": {
|
||||
"from": {
|
||||
"blockId": "j24wz82YG3rjXMgrmCiTLy",
|
||||
"stepId": "1NdXPCiRicqDA8k4JfnXfi"
|
||||
},
|
||||
"to": { "blockId": "bmaKTUXkT2cc3wtKfK7ra71" },
|
||||
"id": "benDCcLMUWNvi6Fg6CXE9H"
|
||||
},
|
||||
"6Tax9rw7L8kmRn9JRD2Mrg": {
|
||||
"from": {
|
||||
"blockId": "bmaKTUXkT2cc3wtKfK7ra71",
|
||||
"stepId": "spHxPWbSqkVZW9gqH86ovC5"
|
||||
},
|
||||
"to": { "blockId": "bnt8fM5Wgc8gBg2iSmUcfJu" },
|
||||
"id": "6Tax9rw7L8kmRn9JRD2Mrg"
|
||||
}
|
||||
},
|
||||
"allIds": ["benDCcLMUWNvi6Fg6CXE9H", "6Tax9rw7L8kmRn9JRD2Mrg"]
|
||||
},
|
||||
"theme": {
|
||||
"chat": {
|
||||
"inputs": {
|
||||
"color": "#303235",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"placeholderColor": "#9095A0"
|
||||
},
|
||||
"buttons": { "color": "#FFFFFF", "backgroundColor": "#0042DA" },
|
||||
"hostBubbles": { "color": "#303235", "backgroundColor": "#F7F8FF" },
|
||||
"guestBubbles": { "color": "#FFFFFF", "backgroundColor": "#FF8E21" }
|
||||
},
|
||||
"general": { "font": "Open Sans", "background": { "type": "None" } }
|
||||
},
|
||||
"settings": {
|
||||
"general": { "isBrandingEnabled": true },
|
||||
"metadata": {
|
||||
"description": "Build beautiful conversational forms and embed them directly in your applications without a line of code. Triple your response rate and collect answers that has more value compared to a traditional form."
|
||||
},
|
||||
"typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 }
|
||||
},
|
||||
"publicId": null
|
||||
}
|
After Width: | Height: | Size: 1.2 MiB |
@ -0,0 +1,155 @@
|
||||
{
|
||||
"id": "ckyltevlb0559z31an8cmkyrp",
|
||||
"createdAt": "2022-01-19T17:24:34.031Z",
|
||||
"updatedAt": "2022-01-19T17:24:34.031Z",
|
||||
"name": "My typebot",
|
||||
"ownerId": "ckyltekzq0533z31ad8opmacz",
|
||||
"publishedTypebotId": null,
|
||||
"folderId": null,
|
||||
"webhooks": { "byId": {}, "allIds": [] },
|
||||
"blocks": {
|
||||
"byId": {
|
||||
"kPupUcEn7TcBGKHUpgK2Q5": {
|
||||
"id": "kPupUcEn7TcBGKHUpgK2Q5",
|
||||
"title": "Start",
|
||||
"stepIds": ["nP5oWm7PxigMupyWpPLq24"],
|
||||
"graphCoordinates": { "x": 0, "y": 0 }
|
||||
},
|
||||
"bi4J5fv9DFn1zPSqGf8eRht": {
|
||||
"id": "bi4J5fv9DFn1zPSqGf8eRht",
|
||||
"title": "Block #2",
|
||||
"graphCoordinates": { "x": 104, "y": 201 },
|
||||
"stepIds": ["scH9qdXwFfAScoavj6UzQNT"]
|
||||
},
|
||||
"bwqGhUsa2SKaxXSrKtapVc8": {
|
||||
"id": "bwqGhUsa2SKaxXSrKtapVc8",
|
||||
"title": "Block #3",
|
||||
"graphCoordinates": { "x": 458, "y": 292 },
|
||||
"stepIds": ["shZdc8Qw48domEbS7vLW5eN"]
|
||||
},
|
||||
"bqmgS9hLUu2RA2oxVv7hMka": {
|
||||
"id": "bqmgS9hLUu2RA2oxVv7hMka",
|
||||
"title": "Block #4",
|
||||
"graphCoordinates": { "x": 102, "y": 432 },
|
||||
"stepIds": ["s4z6G3MGAyhXChU9jakQWer"]
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"kPupUcEn7TcBGKHUpgK2Q5",
|
||||
"bi4J5fv9DFn1zPSqGf8eRht",
|
||||
"bwqGhUsa2SKaxXSrKtapVc8",
|
||||
"bqmgS9hLUu2RA2oxVv7hMka"
|
||||
]
|
||||
},
|
||||
"steps": {
|
||||
"byId": {
|
||||
"nP5oWm7PxigMupyWpPLq24": {
|
||||
"id": "nP5oWm7PxigMupyWpPLq24",
|
||||
"type": "start",
|
||||
"label": "Start",
|
||||
"blockId": "kPupUcEn7TcBGKHUpgK2Q5",
|
||||
"edgeId": "kCLXGLpiM2F6pn4wFYc1f5"
|
||||
},
|
||||
"scH9qdXwFfAScoavj6UzQNT": {
|
||||
"id": "scH9qdXwFfAScoavj6UzQNT",
|
||||
"blockId": "bi4J5fv9DFn1zPSqGf8eRht",
|
||||
"type": "email input",
|
||||
"options": { "variableId": "ifXp66N1meAtoUDcbqWxuD" },
|
||||
"edgeId": "7Czn5hJFUfpkRGtwGnKxtt"
|
||||
},
|
||||
"shZdc8Qw48domEbS7vLW5eN": {
|
||||
"id": "shZdc8Qw48domEbS7vLW5eN",
|
||||
"blockId": "bwqGhUsa2SKaxXSrKtapVc8",
|
||||
"type": "Google Sheets",
|
||||
"edgeId": "eMhGokwHMDRDrynSvpiRje"
|
||||
},
|
||||
"s4z6G3MGAyhXChU9jakQWer": {
|
||||
"id": "s4z6G3MGAyhXChU9jakQWer",
|
||||
"blockId": "bqmgS9hLUu2RA2oxVv7hMka",
|
||||
"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": [
|
||||
"nP5oWm7PxigMupyWpPLq24",
|
||||
"scH9qdXwFfAScoavj6UzQNT",
|
||||
"shZdc8Qw48domEbS7vLW5eN",
|
||||
"s4z6G3MGAyhXChU9jakQWer"
|
||||
]
|
||||
},
|
||||
"choiceItems": { "byId": {}, "allIds": [] },
|
||||
"variables": {
|
||||
"byId": {
|
||||
"ifXp66N1meAtoUDcbqWxuD": {
|
||||
"id": "ifXp66N1meAtoUDcbqWxuD",
|
||||
"name": "Email"
|
||||
}
|
||||
},
|
||||
"allIds": ["ifXp66N1meAtoUDcbqWxuD"]
|
||||
},
|
||||
"edges": {
|
||||
"byId": {
|
||||
"kCLXGLpiM2F6pn4wFYc1f5": {
|
||||
"from": {
|
||||
"blockId": "kPupUcEn7TcBGKHUpgK2Q5",
|
||||
"stepId": "nP5oWm7PxigMupyWpPLq24"
|
||||
},
|
||||
"to": { "blockId": "bi4J5fv9DFn1zPSqGf8eRht" },
|
||||
"id": "kCLXGLpiM2F6pn4wFYc1f5"
|
||||
},
|
||||
"7Czn5hJFUfpkRGtwGnKxtt": {
|
||||
"from": {
|
||||
"blockId": "bi4J5fv9DFn1zPSqGf8eRht",
|
||||
"stepId": "scH9qdXwFfAScoavj6UzQNT"
|
||||
},
|
||||
"to": { "blockId": "bwqGhUsa2SKaxXSrKtapVc8" },
|
||||
"id": "7Czn5hJFUfpkRGtwGnKxtt"
|
||||
},
|
||||
"eMhGokwHMDRDrynSvpiRje": {
|
||||
"from": {
|
||||
"blockId": "bwqGhUsa2SKaxXSrKtapVc8",
|
||||
"stepId": "shZdc8Qw48domEbS7vLW5eN"
|
||||
},
|
||||
"to": { "blockId": "bqmgS9hLUu2RA2oxVv7hMka" },
|
||||
"id": "eMhGokwHMDRDrynSvpiRje"
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"kCLXGLpiM2F6pn4wFYc1f5",
|
||||
"7Czn5hJFUfpkRGtwGnKxtt",
|
||||
"eMhGokwHMDRDrynSvpiRje"
|
||||
]
|
||||
},
|
||||
"theme": {
|
||||
"chat": {
|
||||
"inputs": {
|
||||
"color": "#303235",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"placeholderColor": "#9095A0"
|
||||
},
|
||||
"buttons": { "color": "#FFFFFF", "backgroundColor": "#0042DA" },
|
||||
"hostBubbles": { "color": "#303235", "backgroundColor": "#F7F8FF" },
|
||||
"guestBubbles": { "color": "#FFFFFF", "backgroundColor": "#FF8E21" }
|
||||
},
|
||||
"general": { "font": "Open Sans", "background": { "type": "None" } }
|
||||
},
|
||||
"settings": {
|
||||
"general": { "isBrandingEnabled": true },
|
||||
"metadata": {
|
||||
"description": "Build beautiful conversational forms and embed them directly in your applications without a line of code. Triple your response rate and collect answers that has more value compared to a traditional form."
|
||||
},
|
||||
"typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 }
|
||||
},
|
||||
"publicId": null
|
||||
}
|
After Width: | Height: | Size: 1.3 MiB |
@ -0,0 +1,161 @@
|
||||
{
|
||||
"id": "typebot4",
|
||||
"createdAt": "2022-01-21T07:55:14.727Z",
|
||||
"updatedAt": "2022-01-21T07:55:14.727Z",
|
||||
"name": "My typebot",
|
||||
"ownerId": "user2",
|
||||
"publishedTypebotId": null,
|
||||
"folderId": null,
|
||||
"webhooks": { "byId": {}, "allIds": [] },
|
||||
"blocks": {
|
||||
"byId": {
|
||||
"3kH2sUjVThQDWmqdoKnGk5": {
|
||||
"id": "3kH2sUjVThQDWmqdoKnGk5",
|
||||
"title": "Start",
|
||||
"stepIds": ["oxTsU2C1RX5QHuyY8qjHAM"],
|
||||
"graphCoordinates": { "x": 42, "y": 13 }
|
||||
},
|
||||
"b9mSgu7RKmK4xuiTVQP5Me8": {
|
||||
"id": "b9mSgu7RKmK4xuiTVQP5Me8",
|
||||
"title": "Block #3",
|
||||
"stepIds": ["ssLd2wjExS9qWRur4tZDU1Z"],
|
||||
"graphCoordinates": { "x": 300, "y": 550 }
|
||||
},
|
||||
"bdFW2HHjMoEFmqHtFre9Xi8": {
|
||||
"id": "bdFW2HHjMoEFmqHtFre9Xi8",
|
||||
"title": "Block #2",
|
||||
"stepIds": ["sgkADMK25y9P9V3vjwjBaac", "ssEiEECKSFkA44dGDceHxKw"],
|
||||
"graphCoordinates": { "x": 121, "y": 227 }
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"3kH2sUjVThQDWmqdoKnGk5",
|
||||
"bdFW2HHjMoEFmqHtFre9Xi8",
|
||||
"b9mSgu7RKmK4xuiTVQP5Me8"
|
||||
]
|
||||
},
|
||||
"steps": {
|
||||
"byId": {
|
||||
"oxTsU2C1RX5QHuyY8qjHAM": {
|
||||
"id": "oxTsU2C1RX5QHuyY8qjHAM",
|
||||
"type": "start",
|
||||
"label": "Start",
|
||||
"edgeId": "25yX9DnQgdafpdAjfAu5Fp",
|
||||
"blockId": "3kH2sUjVThQDWmqdoKnGk5"
|
||||
},
|
||||
"sgkADMK25y9P9V3vjwjBaac": {
|
||||
"id": "sgkADMK25y9P9V3vjwjBaac",
|
||||
"type": "text",
|
||||
"blockId": "bdFW2HHjMoEFmqHtFre9Xi8",
|
||||
"content": {
|
||||
"html": "<div>Ready?</div>",
|
||||
"richText": [{ "type": "p", "children": [{ "text": "Ready?" }] }],
|
||||
"plainText": "Ready?"
|
||||
}
|
||||
},
|
||||
"ssEiEECKSFkA44dGDceHxKw": {
|
||||
"id": "ssEiEECKSFkA44dGDceHxKw",
|
||||
"type": "choice input",
|
||||
"edgeId": "oxEEtym3NfDf34NCipzjRQ",
|
||||
"blockId": "bdFW2HHjMoEFmqHtFre9Xi8",
|
||||
"options": { "itemIds": ["q69Ex7LacPrH9QUMeosRnB"] }
|
||||
},
|
||||
"ssLd2wjExS9qWRur4tZDU1Z": {
|
||||
"id": "ssLd2wjExS9qWRur4tZDU1Z",
|
||||
"type": "Webhook",
|
||||
"blockId": "b9mSgu7RKmK4xuiTVQP5Me8",
|
||||
"options": { "webhookId": "4h4Kk3Q1qGy7gFzpZtWVpU" }
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"oxTsU2C1RX5QHuyY8qjHAM",
|
||||
"sgkADMK25y9P9V3vjwjBaac",
|
||||
"ssEiEECKSFkA44dGDceHxKw",
|
||||
"ssLd2wjExS9qWRur4tZDU1Z"
|
||||
]
|
||||
},
|
||||
"choiceItems": {
|
||||
"byId": {
|
||||
"q69Ex7LacPrH9QUMeosRnB": {
|
||||
"id": "q69Ex7LacPrH9QUMeosRnB",
|
||||
"stepId": "ssEiEECKSFkA44dGDceHxKw",
|
||||
"content": "Go"
|
||||
}
|
||||
},
|
||||
"allIds": ["q69Ex7LacPrH9QUMeosRnB"]
|
||||
},
|
||||
"variables": {
|
||||
"byId": {
|
||||
"oASkBtoLqkYNqeakcjZH4L": {
|
||||
"id": "oASkBtoLqkYNqeakcjZH4L",
|
||||
"name": "secret 1"
|
||||
},
|
||||
"4tvkRmf32wiTsXrYoqyhfr": {
|
||||
"id": "4tvkRmf32wiTsXrYoqyhfr",
|
||||
"name": "secret 2"
|
||||
},
|
||||
"jEg1FvkCU5S5owNAxXFsHL": {
|
||||
"id": "jEg1FvkCU5S5owNAxXFsHL",
|
||||
"name": "secret 3"
|
||||
},
|
||||
"rEoE1ehHzgx8X3d3UPGDHg": {
|
||||
"id": "rEoE1ehHzgx8X3d3UPGDHg",
|
||||
"name": "secret 4"
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"oASkBtoLqkYNqeakcjZH4L",
|
||||
"4tvkRmf32wiTsXrYoqyhfr",
|
||||
"jEg1FvkCU5S5owNAxXFsHL",
|
||||
"rEoE1ehHzgx8X3d3UPGDHg"
|
||||
]
|
||||
},
|
||||
"webhooks": {
|
||||
"byId": {
|
||||
"4h4Kk3Q1qGy7gFzpZtWVpU": { "id": "4h4Kk3Q1qGy7gFzpZtWVpU", "url": "" }
|
||||
},
|
||||
"allIds": ["4h4Kk3Q1qGy7gFzpZtWVpU"]
|
||||
},
|
||||
"edges": {
|
||||
"byId": {
|
||||
"25yX9DnQgdafpdAjfAu5Fp": {
|
||||
"id": "25yX9DnQgdafpdAjfAu5Fp",
|
||||
"to": { "blockId": "bdFW2HHjMoEFmqHtFre9Xi8" },
|
||||
"from": {
|
||||
"stepId": "oxTsU2C1RX5QHuyY8qjHAM",
|
||||
"blockId": "3kH2sUjVThQDWmqdoKnGk5"
|
||||
}
|
||||
},
|
||||
"oxEEtym3NfDf34NCipzjRQ": {
|
||||
"id": "oxEEtym3NfDf34NCipzjRQ",
|
||||
"to": { "blockId": "b9mSgu7RKmK4xuiTVQP5Me8" },
|
||||
"from": {
|
||||
"stepId": "ssEiEECKSFkA44dGDceHxKw",
|
||||
"blockId": "bdFW2HHjMoEFmqHtFre9Xi8"
|
||||
}
|
||||
}
|
||||
},
|
||||
"allIds": ["25yX9DnQgdafpdAjfAu5Fp", "oxEEtym3NfDf34NCipzjRQ"]
|
||||
},
|
||||
"theme": {
|
||||
"chat": {
|
||||
"inputs": {
|
||||
"color": "#303235",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"placeholderColor": "#9095A0"
|
||||
},
|
||||
"buttons": { "color": "#FFFFFF", "backgroundColor": "#0042DA" },
|
||||
"hostBubbles": { "color": "#303235", "backgroundColor": "#F7F8FF" },
|
||||
"guestBubbles": { "color": "#FFFFFF", "backgroundColor": "#FF8E21" }
|
||||
},
|
||||
"general": { "font": "Open Sans", "background": { "type": "None" } }
|
||||
},
|
||||
"settings": {
|
||||
"general": { "isBrandingEnabled": true },
|
||||
"metadata": {
|
||||
"description": "Build beautiful conversational forms and embed them directly in your applications without a line of code. Triple your response rate and collect answers that has more value compared to a traditional form."
|
||||
},
|
||||
"typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 }
|
||||
},
|
||||
"publicId": null
|
||||
}
|
@ -0,0 +1,275 @@
|
||||
{
|
||||
"id": "typebot4",
|
||||
"createdAt": "2022-01-21T07:55:14.727Z",
|
||||
"updatedAt": "2022-01-21T07:55:14.727Z",
|
||||
"name": "My typebot",
|
||||
"ownerId": "user2",
|
||||
"publishedTypebotId": null,
|
||||
"folderId": null,
|
||||
"blocks": {
|
||||
"byId": {
|
||||
"3kH2sUjVThQDWmqdoKnGk5": {
|
||||
"id": "3kH2sUjVThQDWmqdoKnGk5",
|
||||
"title": "Start",
|
||||
"stepIds": ["oxTsU2C1RX5QHuyY8qjHAM"],
|
||||
"graphCoordinates": { "x": 42, "y": 13 }
|
||||
},
|
||||
"b9mSgu7RKmK4xuiTVQP5Me8": {
|
||||
"id": "b9mSgu7RKmK4xuiTVQP5Me8",
|
||||
"title": "Block #3",
|
||||
"stepIds": ["ssLd2wjExS9qWRur4tZDU1Z"],
|
||||
"graphCoordinates": { "x": 300, "y": 550 }
|
||||
},
|
||||
"bdFW2HHjMoEFmqHtFre9Xi8": {
|
||||
"id": "bdFW2HHjMoEFmqHtFre9Xi8",
|
||||
"title": "Block #2",
|
||||
"stepIds": ["sgkADMK25y9P9V3vjwjBaac", "ssEiEECKSFkA44dGDceHxKw"],
|
||||
"graphCoordinates": { "x": 121, "y": 227 }
|
||||
},
|
||||
"bmz4rc8r19H2C6b7soxzby4": {
|
||||
"id": "bmz4rc8r19H2C6b7soxzby4",
|
||||
"title": "Block #4",
|
||||
"graphCoordinates": { "x": 632, "y": 279 },
|
||||
"stepIds": ["sgTWsRM1qF2YoYLuGo3Z3pU"]
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"3kH2sUjVThQDWmqdoKnGk5",
|
||||
"bdFW2HHjMoEFmqHtFre9Xi8",
|
||||
"b9mSgu7RKmK4xuiTVQP5Me8",
|
||||
"bmz4rc8r19H2C6b7soxzby4"
|
||||
]
|
||||
},
|
||||
"steps": {
|
||||
"byId": {
|
||||
"oxTsU2C1RX5QHuyY8qjHAM": {
|
||||
"id": "oxTsU2C1RX5QHuyY8qjHAM",
|
||||
"type": "start",
|
||||
"label": "Start",
|
||||
"edgeId": "25yX9DnQgdafpdAjfAu5Fp",
|
||||
"blockId": "3kH2sUjVThQDWmqdoKnGk5"
|
||||
},
|
||||
"sgkADMK25y9P9V3vjwjBaac": {
|
||||
"id": "sgkADMK25y9P9V3vjwjBaac",
|
||||
"type": "text",
|
||||
"blockId": "bdFW2HHjMoEFmqHtFre9Xi8",
|
||||
"content": {
|
||||
"html": "<div>Ready?</div>",
|
||||
"richText": [{ "type": "p", "children": [{ "text": "Ready?" }] }],
|
||||
"plainText": "Ready?"
|
||||
}
|
||||
},
|
||||
"ssEiEECKSFkA44dGDceHxKw": {
|
||||
"id": "ssEiEECKSFkA44dGDceHxKw",
|
||||
"type": "choice input",
|
||||
"edgeId": "oxEEtym3NfDf34NCipzjRQ",
|
||||
"blockId": "bdFW2HHjMoEFmqHtFre9Xi8",
|
||||
"options": { "itemIds": ["q69Ex7LacPrH9QUMeosRnB"] }
|
||||
},
|
||||
"ssLd2wjExS9qWRur4tZDU1Z": {
|
||||
"id": "ssLd2wjExS9qWRur4tZDU1Z",
|
||||
"type": "Webhook",
|
||||
"blockId": "b9mSgu7RKmK4xuiTVQP5Me8",
|
||||
"options": {
|
||||
"webhookId": "4h4Kk3Q1qGy7gFzpZtWVpU",
|
||||
"variablesForTest": {
|
||||
"byId": {
|
||||
"6pMn1xm1y3xWVSdJetMAJH": {
|
||||
"id": "6pMn1xm1y3xWVSdJetMAJH",
|
||||
"variableId": "oASkBtoLqkYNqeakcjZH4L",
|
||||
"value": "secret1"
|
||||
},
|
||||
"ettAiB75uoFWnJyPS7gn5k": {
|
||||
"id": "ettAiB75uoFWnJyPS7gn5k",
|
||||
"variableId": "4tvkRmf32wiTsXrYoqyhfr",
|
||||
"value": "secret2"
|
||||
},
|
||||
"kKpD3Q4YvFQ7CGWiZxJF4s": {
|
||||
"id": "kKpD3Q4YvFQ7CGWiZxJF4s",
|
||||
"variableId": "jEg1FvkCU5S5owNAxXFsHL",
|
||||
"value": "secret3"
|
||||
},
|
||||
"xjUC5Q3msXCw9fwqpNdoSx": {
|
||||
"id": "xjUC5Q3msXCw9fwqpNdoSx",
|
||||
"variableId": "rEoE1ehHzgx8X3d3UPGDHg",
|
||||
"value": "secret4"
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"6pMn1xm1y3xWVSdJetMAJH",
|
||||
"ettAiB75uoFWnJyPS7gn5k",
|
||||
"kKpD3Q4YvFQ7CGWiZxJF4s",
|
||||
"xjUC5Q3msXCw9fwqpNdoSx"
|
||||
]
|
||||
},
|
||||
"responseVariableMapping": {
|
||||
"byId": {
|
||||
"o53h6M1sgHJfDTY5C3YEaT": {
|
||||
"id": "o53h6M1sgHJfDTY5C3YEaT",
|
||||
"bodyPath": "data[0].name",
|
||||
"variableId": "4kVx5uf8W1XP6WsfJEvt8v"
|
||||
}
|
||||
},
|
||||
"allIds": ["o53h6M1sgHJfDTY5C3YEaT"]
|
||||
}
|
||||
},
|
||||
"edgeId": "81SjKnxuUgrPmXvvJJihHM"
|
||||
},
|
||||
"sgTWsRM1qF2YoYLuGo3Z3pU": {
|
||||
"id": "sgTWsRM1qF2YoYLuGo3Z3pU",
|
||||
"blockId": "bmz4rc8r19H2C6b7soxzby4",
|
||||
"type": "text",
|
||||
"content": {
|
||||
"html": "<div>His name is {{Name}}</div>",
|
||||
"richText": [
|
||||
{ "type": "p", "children": [{ "text": "His name is {{Name}}" }] }
|
||||
],
|
||||
"plainText": "His name is {{Name}}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"oxTsU2C1RX5QHuyY8qjHAM",
|
||||
"sgkADMK25y9P9V3vjwjBaac",
|
||||
"ssEiEECKSFkA44dGDceHxKw",
|
||||
"ssLd2wjExS9qWRur4tZDU1Z",
|
||||
"sgTWsRM1qF2YoYLuGo3Z3pU"
|
||||
]
|
||||
},
|
||||
"choiceItems": {
|
||||
"byId": {
|
||||
"q69Ex7LacPrH9QUMeosRnB": {
|
||||
"id": "q69Ex7LacPrH9QUMeosRnB",
|
||||
"stepId": "ssEiEECKSFkA44dGDceHxKw",
|
||||
"content": "Go"
|
||||
}
|
||||
},
|
||||
"allIds": ["q69Ex7LacPrH9QUMeosRnB"]
|
||||
},
|
||||
"webhooks": { "byId": {}, "allIds": [] },
|
||||
"variables": {
|
||||
"byId": {
|
||||
"4tvkRmf32wiTsXrYoqyhfr": {
|
||||
"id": "4tvkRmf32wiTsXrYoqyhfr",
|
||||
"name": "secret 2",
|
||||
"value": "secret2"
|
||||
},
|
||||
"jEg1FvkCU5S5owNAxXFsHL": {
|
||||
"id": "jEg1FvkCU5S5owNAxXFsHL",
|
||||
"name": "secret 3",
|
||||
"value": "secret3"
|
||||
},
|
||||
"oASkBtoLqkYNqeakcjZH4L": {
|
||||
"id": "oASkBtoLqkYNqeakcjZH4L",
|
||||
"name": "secret 1",
|
||||
"value": "secret1"
|
||||
},
|
||||
"rEoE1ehHzgx8X3d3UPGDHg": {
|
||||
"id": "rEoE1ehHzgx8X3d3UPGDHg",
|
||||
"name": "secret 4",
|
||||
"value": "secret4"
|
||||
},
|
||||
"4kVx5uf8W1XP6WsfJEvt8v": {
|
||||
"id": "4kVx5uf8W1XP6WsfJEvt8v",
|
||||
"name": "Name"
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"oASkBtoLqkYNqeakcjZH4L",
|
||||
"4tvkRmf32wiTsXrYoqyhfr",
|
||||
"jEg1FvkCU5S5owNAxXFsHL",
|
||||
"rEoE1ehHzgx8X3d3UPGDHg",
|
||||
"4kVx5uf8W1XP6WsfJEvt8v"
|
||||
]
|
||||
},
|
||||
"webhooks": {
|
||||
"byId": {
|
||||
"4h4Kk3Q1qGy7gFzpZtWVpU": {
|
||||
"id": "4h4Kk3Q1qGy7gFzpZtWVpU",
|
||||
"url": "http://localhost:3000/api/mock/webhook",
|
||||
"queryParams": {
|
||||
"byId": {
|
||||
"hwGB11cA7RaYnaqH7gYyuQ": {
|
||||
"id": "hwGB11cA7RaYnaqH7gYyuQ",
|
||||
"key": "firstParam",
|
||||
"value": "{{secret 1}}"
|
||||
},
|
||||
"6ux2FZjhNc4vfqNUDuCkxn": {
|
||||
"id": "6ux2FZjhNc4vfqNUDuCkxn",
|
||||
"key": "secondParam",
|
||||
"value": "{{secret 2}}"
|
||||
}
|
||||
},
|
||||
"allIds": ["hwGB11cA7RaYnaqH7gYyuQ", "6ux2FZjhNc4vfqNUDuCkxn"]
|
||||
},
|
||||
"headers": {
|
||||
"byId": {
|
||||
"ayTB2cFRKMo6oH9t9KS8SA": {
|
||||
"id": "ayTB2cFRKMo6oH9t9KS8SA",
|
||||
"key": "Custom-Typebot",
|
||||
"value": "{{secret 3}}"
|
||||
}
|
||||
},
|
||||
"allIds": ["ayTB2cFRKMo6oH9t9KS8SA"]
|
||||
},
|
||||
"method": "POST",
|
||||
"body": "{ \"customField\": \"{{secret 4}}\" }"
|
||||
}
|
||||
},
|
||||
"allIds": ["4h4Kk3Q1qGy7gFzpZtWVpU"]
|
||||
},
|
||||
"edges": {
|
||||
"byId": {
|
||||
"25yX9DnQgdafpdAjfAu5Fp": {
|
||||
"id": "25yX9DnQgdafpdAjfAu5Fp",
|
||||
"to": { "blockId": "bdFW2HHjMoEFmqHtFre9Xi8" },
|
||||
"from": {
|
||||
"stepId": "oxTsU2C1RX5QHuyY8qjHAM",
|
||||
"blockId": "3kH2sUjVThQDWmqdoKnGk5"
|
||||
}
|
||||
},
|
||||
"oxEEtym3NfDf34NCipzjRQ": {
|
||||
"id": "oxEEtym3NfDf34NCipzjRQ",
|
||||
"to": { "blockId": "b9mSgu7RKmK4xuiTVQP5Me8" },
|
||||
"from": {
|
||||
"stepId": "ssEiEECKSFkA44dGDceHxKw",
|
||||
"blockId": "bdFW2HHjMoEFmqHtFre9Xi8"
|
||||
}
|
||||
},
|
||||
"81SjKnxuUgrPmXvvJJihHM": {
|
||||
"from": {
|
||||
"blockId": "b9mSgu7RKmK4xuiTVQP5Me8",
|
||||
"stepId": "ssLd2wjExS9qWRur4tZDU1Z"
|
||||
},
|
||||
"to": { "blockId": "bmz4rc8r19H2C6b7soxzby4" },
|
||||
"id": "81SjKnxuUgrPmXvvJJihHM"
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"25yX9DnQgdafpdAjfAu5Fp",
|
||||
"oxEEtym3NfDf34NCipzjRQ",
|
||||
"81SjKnxuUgrPmXvvJJihHM"
|
||||
]
|
||||
},
|
||||
"theme": {
|
||||
"chat": {
|
||||
"inputs": {
|
||||
"color": "#303235",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"placeholderColor": "#9095A0"
|
||||
},
|
||||
"buttons": { "color": "#FFFFFF", "backgroundColor": "#0042DA" },
|
||||
"hostBubbles": { "color": "#303235", "backgroundColor": "#F7F8FF" },
|
||||
"guestBubbles": { "color": "#FFFFFF", "backgroundColor": "#FF8E21" }
|
||||
},
|
||||
"general": { "font": "Open Sans", "background": { "type": "None" } }
|
||||
},
|
||||
"settings": {
|
||||
"general": { "isBrandingEnabled": true },
|
||||
"metadata": {
|
||||
"description": "Build beautiful conversational forms and embed them directly in your applications without a line of code. Triple your response rate and collect answers that has more value compared to a traditional form."
|
||||
},
|
||||
"typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 }
|
||||
},
|
||||
"publicId": null
|
||||
}
|
After Width: | Height: | Size: 283 KiB |
247
apps/builder/playwright/fixtures/typebots/logic/condition.json
Normal file
@ -0,0 +1,247 @@
|
||||
{
|
||||
"id": "ckylsd52p0114z31aobllswmu",
|
||||
"createdAt": "2022-01-19T16:55:13.393Z",
|
||||
"updatedAt": "2022-01-19T16:55:13.393Z",
|
||||
"name": "My typebot",
|
||||
"ownerId": "ckylsbdf60088z31ayqytest6",
|
||||
"publishedTypebotId": null,
|
||||
"folderId": null,
|
||||
"webhooks": { "byId": {}, "allIds": [] },
|
||||
"blocks": {
|
||||
"byId": {
|
||||
"2x83WHtEBkiv7pk7KgqJwZ": {
|
||||
"id": "2x83WHtEBkiv7pk7KgqJwZ",
|
||||
"title": "Start",
|
||||
"stepIds": ["1A76iZBgXG7hvkG2koCxe4"],
|
||||
"graphCoordinates": { "x": 0, "y": 0 }
|
||||
},
|
||||
"bwga7RwqQWbowdHph27DM1N": {
|
||||
"id": "bwga7RwqQWbowdHph27DM1N",
|
||||
"title": "Block #2",
|
||||
"graphCoordinates": { "x": 78, "y": 224 },
|
||||
"stepIds": ["srwUKaUFFmehppJ2ZDqp4xG", "sxvzuo48GHi3AcAfmiFyYC1"]
|
||||
},
|
||||
"bu8whx817bJBG37FQrtD5dD": {
|
||||
"id": "bu8whx817bJBG37FQrtD5dD",
|
||||
"title": "Block #3",
|
||||
"graphCoordinates": { "x": 430, "y": 287 },
|
||||
"stepIds": ["ituVWW1AvQeVdFHTwsiVao", "5SLc4whZooZVUfr1bmTNSC"]
|
||||
},
|
||||
"b59jwmEdwZUvJszV394x44u": {
|
||||
"id": "b59jwmEdwZUvJszV394x44u",
|
||||
"title": "Block #4",
|
||||
"graphCoordinates": { "x": 844, "y": 185 },
|
||||
"stepIds": ["sm1YcKTL9cQMCGywzo1wyBB"]
|
||||
},
|
||||
"baVF9HqhuSnLDZqY9eRPpcp": {
|
||||
"id": "baVF9HqhuSnLDZqY9eRPpcp",
|
||||
"title": "Block #5",
|
||||
"graphCoordinates": { "x": 841, "y": 356 },
|
||||
"stepIds": ["sb3o6J8Fybg6u8KuayKviJq"]
|
||||
},
|
||||
"b9aEH46RHuZWTdQwZJ6KBWR": {
|
||||
"id": "b9aEH46RHuZWTdQwZJ6KBWR",
|
||||
"title": "Block #6",
|
||||
"graphCoordinates": { "x": 839, "y": 523 },
|
||||
"stepIds": ["scKogEJSTq4kPeHRhwTTjit"]
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"2x83WHtEBkiv7pk7KgqJwZ",
|
||||
"bwga7RwqQWbowdHph27DM1N",
|
||||
"bu8whx817bJBG37FQrtD5dD",
|
||||
"b59jwmEdwZUvJszV394x44u",
|
||||
"baVF9HqhuSnLDZqY9eRPpcp",
|
||||
"b9aEH46RHuZWTdQwZJ6KBWR"
|
||||
]
|
||||
},
|
||||
"steps": {
|
||||
"byId": {
|
||||
"1A76iZBgXG7hvkG2koCxe4": {
|
||||
"id": "1A76iZBgXG7hvkG2koCxe4",
|
||||
"type": "start",
|
||||
"label": "Start",
|
||||
"blockId": "2x83WHtEBkiv7pk7KgqJwZ",
|
||||
"edgeId": "jjNy2hYgrQgPS9EBMKA7MH"
|
||||
},
|
||||
"srwUKaUFFmehppJ2ZDqp4xG": {
|
||||
"id": "srwUKaUFFmehppJ2ZDqp4xG",
|
||||
"blockId": "bwga7RwqQWbowdHph27DM1N",
|
||||
"type": "text",
|
||||
"content": {
|
||||
"html": "<div>How old are you?</div>",
|
||||
"richText": [
|
||||
{ "type": "p", "children": [{ "text": "How old are you?" }] }
|
||||
],
|
||||
"plainText": "How old are you?"
|
||||
}
|
||||
},
|
||||
"sxvzuo48GHi3AcAfmiFyYC1": {
|
||||
"id": "sxvzuo48GHi3AcAfmiFyYC1",
|
||||
"blockId": "bwga7RwqQWbowdHph27DM1N",
|
||||
"type": "number input",
|
||||
"options": { "variableId": "dEz689uVm8AxUM8TrbQd2t" },
|
||||
"edgeId": "7mcWaWohM9zGtLX8ZSnqFy"
|
||||
},
|
||||
"ituVWW1AvQeVdFHTwsiVao": {
|
||||
"id": "ituVWW1AvQeVdFHTwsiVao",
|
||||
"blockId": "bu8whx817bJBG37FQrtD5dD",
|
||||
"type": "Condition",
|
||||
"options": {
|
||||
"comparisons": {
|
||||
"byId": {},
|
||||
"allIds": []
|
||||
},
|
||||
"logicalOperator": "AND"
|
||||
},
|
||||
"trueEdgeId": "iBPsFyBsPv6Rbdfo2QdJyi"
|
||||
},
|
||||
"5SLc4whZooZVUfr1bmTNSC": {
|
||||
"id": "5SLc4whZooZVUfr1bmTNSC",
|
||||
"blockId": "bu8whx817bJBG37FQrtD5dD",
|
||||
"type": "Condition",
|
||||
"options": {
|
||||
"comparisons": {
|
||||
"byId": {},
|
||||
"allIds": []
|
||||
},
|
||||
"logicalOperator": "AND"
|
||||
},
|
||||
"trueEdgeId": "354PJ2jD5U3J2APqLsPJrp",
|
||||
"falseEdgeId": "94bmeCLigEUUpWYw2xsAVB"
|
||||
},
|
||||
"sm1YcKTL9cQMCGywzo1wyBB": {
|
||||
"id": "sm1YcKTL9cQMCGywzo1wyBB",
|
||||
"blockId": "b59jwmEdwZUvJszV394x44u",
|
||||
"type": "text",
|
||||
"content": {
|
||||
"html": "<div>You are older than 80</div>",
|
||||
"richText": [
|
||||
{ "type": "p", "children": [{ "text": "You are older than 80" }] }
|
||||
],
|
||||
"plainText": "You are older than 80"
|
||||
}
|
||||
},
|
||||
"sb3o6J8Fybg6u8KuayKviJq": {
|
||||
"id": "sb3o6J8Fybg6u8KuayKviJq",
|
||||
"blockId": "baVF9HqhuSnLDZqY9eRPpcp",
|
||||
"type": "text",
|
||||
"content": {
|
||||
"html": "<div>You are older than 20</div>",
|
||||
"richText": [
|
||||
{ "type": "p", "children": [{ "text": "You are older than 20" }] }
|
||||
],
|
||||
"plainText": "You are older than 20"
|
||||
}
|
||||
},
|
||||
"scKogEJSTq4kPeHRhwTTjit": {
|
||||
"id": "scKogEJSTq4kPeHRhwTTjit",
|
||||
"blockId": "b9aEH46RHuZWTdQwZJ6KBWR",
|
||||
"type": "text",
|
||||
"content": {
|
||||
"html": "<div>You are younger than 20</div>",
|
||||
"richText": [
|
||||
{ "type": "p", "children": [{ "text": "You are younger than 20" }] }
|
||||
],
|
||||
"plainText": "You are younger than 20"
|
||||
}
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"1A76iZBgXG7hvkG2koCxe4",
|
||||
"srwUKaUFFmehppJ2ZDqp4xG",
|
||||
"sxvzuo48GHi3AcAfmiFyYC1",
|
||||
"ituVWW1AvQeVdFHTwsiVao",
|
||||
"5SLc4whZooZVUfr1bmTNSC",
|
||||
"sxvzuo48GHi3AcAfmiFyYC1",
|
||||
"sm1YcKTL9cQMCGywzo1wyBB",
|
||||
"sb3o6J8Fybg6u8KuayKviJq",
|
||||
"scKogEJSTq4kPeHRhwTTjit"
|
||||
]
|
||||
},
|
||||
"choiceItems": { "byId": {}, "allIds": [] },
|
||||
"variables": {
|
||||
"byId": {
|
||||
"dEz689uVm8AxUM8TrbQd2t": {
|
||||
"id": "dEz689uVm8AxUM8TrbQd2t",
|
||||
"name": "Age"
|
||||
}
|
||||
},
|
||||
"allIds": ["dEz689uVm8AxUM8TrbQd2t"]
|
||||
},
|
||||
"edges": {
|
||||
"byId": {
|
||||
"jjNy2hYgrQgPS9EBMKA7MH": {
|
||||
"from": {
|
||||
"blockId": "2x83WHtEBkiv7pk7KgqJwZ",
|
||||
"stepId": "1A76iZBgXG7hvkG2koCxe4"
|
||||
},
|
||||
"to": { "blockId": "bwga7RwqQWbowdHph27DM1N" },
|
||||
"id": "jjNy2hYgrQgPS9EBMKA7MH"
|
||||
},
|
||||
"iBPsFyBsPv6Rbdfo2QdJyi": {
|
||||
"from": {
|
||||
"blockId": "bu8whx817bJBG37FQrtD5dD",
|
||||
"stepId": "ituVWW1AvQeVdFHTwsiVao",
|
||||
"conditionType": "true"
|
||||
},
|
||||
"to": { "blockId": "b59jwmEdwZUvJszV394x44u" },
|
||||
"id": "iBPsFyBsPv6Rbdfo2QdJyi"
|
||||
},
|
||||
"354PJ2jD5U3J2APqLsPJrp": {
|
||||
"from": {
|
||||
"blockId": "bu8whx817bJBG37FQrtD5dD",
|
||||
"stepId": "5SLc4whZooZVUfr1bmTNSC",
|
||||
"conditionType": "true"
|
||||
},
|
||||
"to": { "blockId": "baVF9HqhuSnLDZqY9eRPpcp" },
|
||||
"id": "354PJ2jD5U3J2APqLsPJrp"
|
||||
},
|
||||
"94bmeCLigEUUpWYw2xsAVB": {
|
||||
"from": {
|
||||
"blockId": "bu8whx817bJBG37FQrtD5dD",
|
||||
"stepId": "5SLc4whZooZVUfr1bmTNSC",
|
||||
"conditionType": "false"
|
||||
},
|
||||
"to": { "blockId": "b9aEH46RHuZWTdQwZJ6KBWR" },
|
||||
"id": "94bmeCLigEUUpWYw2xsAVB"
|
||||
},
|
||||
"7mcWaWohM9zGtLX8ZSnqFy": {
|
||||
"from": {
|
||||
"blockId": "bwga7RwqQWbowdHph27DM1N",
|
||||
"stepId": "sxvzuo48GHi3AcAfmiFyYC1"
|
||||
},
|
||||
"to": { "blockId": "bu8whx817bJBG37FQrtD5dD" },
|
||||
"id": "7mcWaWohM9zGtLX8ZSnqFy"
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"jjNy2hYgrQgPS9EBMKA7MH",
|
||||
"iBPsFyBsPv6Rbdfo2QdJyi",
|
||||
"354PJ2jD5U3J2APqLsPJrp",
|
||||
"94bmeCLigEUUpWYw2xsAVB",
|
||||
"7mcWaWohM9zGtLX8ZSnqFy"
|
||||
]
|
||||
},
|
||||
"theme": {
|
||||
"chat": {
|
||||
"inputs": {
|
||||
"color": "#303235",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"placeholderColor": "#9095A0"
|
||||
},
|
||||
"buttons": { "color": "#FFFFFF", "backgroundColor": "#0042DA" },
|
||||
"hostBubbles": { "color": "#303235", "backgroundColor": "#F7F8FF" },
|
||||
"guestBubbles": { "color": "#FFFFFF", "backgroundColor": "#FF8E21" }
|
||||
},
|
||||
"general": { "font": "Open Sans", "background": { "type": "None" } }
|
||||
},
|
||||
"settings": {
|
||||
"general": { "isBrandingEnabled": true },
|
||||
"metadata": {
|
||||
"description": "Build beautiful conversational forms and embed them directly in your applications without a line of code. Triple your response rate and collect answers that has more value compared to a traditional form."
|
||||
},
|
||||
"typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 }
|
||||
},
|
||||
"publicId": null
|
||||
}
|
BIN
apps/builder/playwright/fixtures/typebots/logic/condition.png
Normal file
After Width: | Height: | Size: 1.4 MiB |
120
apps/builder/playwright/fixtures/typebots/logic/redirect.json
Normal file
@ -0,0 +1,120 @@
|
||||
{
|
||||
"id": "ckymkfh1e00562z1a3fjoua3e",
|
||||
"createdAt": "2022-01-20T06:00:51.458Z",
|
||||
"updatedAt": "2022-01-20T06:00:51.458Z",
|
||||
"name": "My typebot",
|
||||
"ownerId": "ckymkff1100362z1a85juyoa8",
|
||||
"publishedTypebotId": null,
|
||||
"folderId": null,
|
||||
"webhooks": { "byId": {}, "allIds": [] },
|
||||
"blocks": {
|
||||
"byId": {
|
||||
"bsVJfEW7EZrUnAi9s5ev17": {
|
||||
"id": "bsVJfEW7EZrUnAi9s5ev17",
|
||||
"title": "Start",
|
||||
"stepIds": ["9Ck2yveNjZNHhjyc4HCJAL"],
|
||||
"graphCoordinates": { "x": 0, "y": 0 }
|
||||
},
|
||||
"bmdnpyvzopZ8YVfqsJY7Q8K": {
|
||||
"id": "bmdnpyvzopZ8YVfqsJY7Q8K",
|
||||
"title": "Block #2",
|
||||
"graphCoordinates": { "x": 68, "y": 229 },
|
||||
"stepIds": ["sas16Qqf4TmZEXSexmYpmSd"]
|
||||
},
|
||||
"bnsxmer7DD2R9DogoXTsvHJ": {
|
||||
"id": "bnsxmer7DD2R9DogoXTsvHJ",
|
||||
"title": "Block #3",
|
||||
"graphCoordinates": { "x": 491, "y": 239 },
|
||||
"stepIds": ["sqNGop2aYkXRvJqb9nGtFbD"]
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"bsVJfEW7EZrUnAi9s5ev17",
|
||||
"bmdnpyvzopZ8YVfqsJY7Q8K",
|
||||
"bnsxmer7DD2R9DogoXTsvHJ"
|
||||
]
|
||||
},
|
||||
"steps": {
|
||||
"byId": {
|
||||
"9Ck2yveNjZNHhjyc4HCJAL": {
|
||||
"id": "9Ck2yveNjZNHhjyc4HCJAL",
|
||||
"type": "start",
|
||||
"label": "Start",
|
||||
"blockId": "bsVJfEW7EZrUnAi9s5ev17",
|
||||
"edgeId": "totLsWG6AQfcFT39CsZwDy"
|
||||
},
|
||||
"sas16Qqf4TmZEXSexmYpmSd": {
|
||||
"id": "sas16Qqf4TmZEXSexmYpmSd",
|
||||
"blockId": "bmdnpyvzopZ8YVfqsJY7Q8K",
|
||||
"type": "choice input",
|
||||
"options": { "itemIds": ["mAgynXh3zmkmWzNyPGVAcf"] }
|
||||
},
|
||||
"sqNGop2aYkXRvJqb9nGtFbD": {
|
||||
"id": "sqNGop2aYkXRvJqb9nGtFbD",
|
||||
"blockId": "bnsxmer7DD2R9DogoXTsvHJ",
|
||||
"type": "Redirect",
|
||||
"options": { "isNewTab": false }
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"9Ck2yveNjZNHhjyc4HCJAL",
|
||||
"sas16Qqf4TmZEXSexmYpmSd",
|
||||
"sqNGop2aYkXRvJqb9nGtFbD"
|
||||
]
|
||||
},
|
||||
"choiceItems": {
|
||||
"byId": {
|
||||
"mAgynXh3zmkmWzNyPGVAcf": {
|
||||
"id": "mAgynXh3zmkmWzNyPGVAcf",
|
||||
"stepId": "sas16Qqf4TmZEXSexmYpmSd",
|
||||
"content": "Go to URL",
|
||||
"edgeId": "7KgqWB88ufzhDwzvwHuEbN"
|
||||
}
|
||||
},
|
||||
"allIds": ["mAgynXh3zmkmWzNyPGVAcf"]
|
||||
},
|
||||
"variables": { "byId": {}, "allIds": [] },
|
||||
"edges": {
|
||||
"byId": {
|
||||
"totLsWG6AQfcFT39CsZwDy": {
|
||||
"from": {
|
||||
"blockId": "bsVJfEW7EZrUnAi9s5ev17",
|
||||
"stepId": "9Ck2yveNjZNHhjyc4HCJAL"
|
||||
},
|
||||
"to": { "blockId": "bmdnpyvzopZ8YVfqsJY7Q8K" },
|
||||
"id": "totLsWG6AQfcFT39CsZwDy"
|
||||
},
|
||||
"7KgqWB88ufzhDwzvwHuEbN": {
|
||||
"from": {
|
||||
"blockId": "bmdnpyvzopZ8YVfqsJY7Q8K",
|
||||
"stepId": "sas16Qqf4TmZEXSexmYpmSd",
|
||||
"nodeId": "mAgynXh3zmkmWzNyPGVAcf"
|
||||
},
|
||||
"to": { "blockId": "bnsxmer7DD2R9DogoXTsvHJ" },
|
||||
"id": "7KgqWB88ufzhDwzvwHuEbN"
|
||||
}
|
||||
},
|
||||
"allIds": ["totLsWG6AQfcFT39CsZwDy", "7KgqWB88ufzhDwzvwHuEbN"]
|
||||
},
|
||||
"theme": {
|
||||
"chat": {
|
||||
"inputs": {
|
||||
"color": "#303235",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"placeholderColor": "#9095A0"
|
||||
},
|
||||
"buttons": { "color": "#FFFFFF", "backgroundColor": "#0042DA" },
|
||||
"hostBubbles": { "color": "#303235", "backgroundColor": "#F7F8FF" },
|
||||
"guestBubbles": { "color": "#FFFFFF", "backgroundColor": "#FF8E21" }
|
||||
},
|
||||
"general": { "font": "Open Sans", "background": { "type": "None" } }
|
||||
},
|
||||
"settings": {
|
||||
"general": { "isBrandingEnabled": true },
|
||||
"metadata": {
|
||||
"description": "Build beautiful conversational forms and embed them directly in your applications without a line of code. Triple your response rate and collect answers that has more value compared to a traditional form."
|
||||
},
|
||||
"typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 }
|
||||
},
|
||||
"publicId": null
|
||||
}
|
BIN
apps/builder/playwright/fixtures/typebots/logic/redirect.png
Normal file
After Width: | Height: | Size: 1.2 MiB |
171
apps/builder/playwright/fixtures/typebots/logic/setVariable.json
Normal file
@ -0,0 +1,171 @@
|
||||
{
|
||||
"id": "ckylrr3qh0030fn1a3nszzxiu",
|
||||
"createdAt": "2022-01-19T16:38:05.225Z",
|
||||
"updatedAt": "2022-01-19T16:38:05.225Z",
|
||||
"name": "My typebot",
|
||||
"ownerId": "ckylrpsmt0006fn1ah956d0z1",
|
||||
"publishedTypebotId": null,
|
||||
"folderId": null,
|
||||
"webhooks": { "byId": {}, "allIds": [] },
|
||||
"blocks": {
|
||||
"byId": {
|
||||
"kmUzhRFzSKjkaipYNcku9S": {
|
||||
"id": "kmUzhRFzSKjkaipYNcku9S",
|
||||
"title": "Start",
|
||||
"stepIds": ["6XgP3JoCh7Y4M8GCX9DKym"],
|
||||
"graphCoordinates": { "x": 0, "y": 0 }
|
||||
},
|
||||
"bwWRAaX5m6NZyZ9jjpXmWSb": {
|
||||
"id": "bwWRAaX5m6NZyZ9jjpXmWSb",
|
||||
"title": "Block #2",
|
||||
"graphCoordinates": { "x": -21, "y": 221 },
|
||||
"stepIds": ["sqMVMXeRYp4inLcRqej2Wac", "s8n3nJajsBaYqrFeRYVvcf6"]
|
||||
},
|
||||
"baUyUnNBxZzPe1z5PqE4NkD": {
|
||||
"id": "baUyUnNBxZzPe1z5PqE4NkD",
|
||||
"title": "Block #3",
|
||||
"graphCoordinates": { "x": 375, "y": 280 },
|
||||
"stepIds": ["shfL5ueQDuj2RPcJPWZGArT", "sugJ6xN3jFys1CjWfsxGhiJ"]
|
||||
},
|
||||
"bwkKNpJmAFCCLbZSnPnnLnR": {
|
||||
"id": "bwkKNpJmAFCCLbZSnPnnLnR",
|
||||
"title": "Block #4",
|
||||
"graphCoordinates": { "x": 421, "y": 42 },
|
||||
"stepIds": ["shR7ae3iNEvB6arCSu7wVFF"]
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"kmUzhRFzSKjkaipYNcku9S",
|
||||
"bwWRAaX5m6NZyZ9jjpXmWSb",
|
||||
"baUyUnNBxZzPe1z5PqE4NkD",
|
||||
"bwkKNpJmAFCCLbZSnPnnLnR"
|
||||
]
|
||||
},
|
||||
"steps": {
|
||||
"byId": {
|
||||
"6XgP3JoCh7Y4M8GCX9DKym": {
|
||||
"id": "6XgP3JoCh7Y4M8GCX9DKym",
|
||||
"type": "start",
|
||||
"label": "Start",
|
||||
"blockId": "kmUzhRFzSKjkaipYNcku9S",
|
||||
"edgeId": "ahfJ4fUuvxX2dcBMk876tf"
|
||||
},
|
||||
"s8n3nJajsBaYqrFeRYVvcf6": {
|
||||
"id": "s8n3nJajsBaYqrFeRYVvcf6",
|
||||
"blockId": "bwWRAaX5m6NZyZ9jjpXmWSb",
|
||||
"type": "number input",
|
||||
"edgeId": "dcJedLC7qsLtsmm1wbiFFc",
|
||||
"options": {
|
||||
"labels": {
|
||||
"placeholder": "Type a number..."
|
||||
}
|
||||
}
|
||||
},
|
||||
"sqMVMXeRYp4inLcRqej2Wac": {
|
||||
"id": "sqMVMXeRYp4inLcRqej2Wac",
|
||||
"blockId": "bwWRAaX5m6NZyZ9jjpXmWSb",
|
||||
"type": "text",
|
||||
"content": {
|
||||
"html": "<div>How old are you?</div>",
|
||||
"richText": [
|
||||
{ "type": "p", "children": [{ "text": "How old are you?" }] }
|
||||
],
|
||||
"plainText": "How old are you?"
|
||||
}
|
||||
},
|
||||
"shfL5ueQDuj2RPcJPWZGArT": {
|
||||
"id": "shfL5ueQDuj2RPcJPWZGArT",
|
||||
"blockId": "baUyUnNBxZzPe1z5PqE4NkD",
|
||||
"type": "Set variable",
|
||||
"options": {}
|
||||
},
|
||||
"sugJ6xN3jFys1CjWfsxGhiJ": {
|
||||
"id": "sugJ6xN3jFys1CjWfsxGhiJ",
|
||||
"blockId": "baUyUnNBxZzPe1z5PqE4NkD",
|
||||
"type": "Set variable",
|
||||
"edgeId": "sA5gvCVVBVYdGsdeSGF5ei",
|
||||
"options": {}
|
||||
},
|
||||
"shR7ae3iNEvB6arCSu7wVFF": {
|
||||
"id": "shR7ae3iNEvB6arCSu7wVFF",
|
||||
"blockId": "bwkKNpJmAFCCLbZSnPnnLnR",
|
||||
"type": "text",
|
||||
"content": {
|
||||
"html": "<div>Total: {{Total}}</div><div>Custom var: {{Custom var}}</div>",
|
||||
"richText": [
|
||||
{ "type": "p", "children": [{ "text": "Total: {{Total}}" }] },
|
||||
{
|
||||
"type": "p",
|
||||
"children": [{ "text": "Custom var: {{Custom var}}" }]
|
||||
}
|
||||
],
|
||||
"plainText": "Total: {{Total}}Custom var: {{Custom var}}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"6XgP3JoCh7Y4M8GCX9DKym",
|
||||
"s8n3nJajsBaYqrFeRYVvcf6",
|
||||
"sqMVMXeRYp4inLcRqej2Wac",
|
||||
"shfL5ueQDuj2RPcJPWZGArT",
|
||||
"sugJ6xN3jFys1CjWfsxGhiJ",
|
||||
"shR7ae3iNEvB6arCSu7wVFF"
|
||||
]
|
||||
},
|
||||
"choiceItems": { "byId": {}, "allIds": [] },
|
||||
"variables": { "byId": {}, "allIds": [] },
|
||||
"edges": {
|
||||
"byId": {
|
||||
"ahfJ4fUuvxX2dcBMk876tf": {
|
||||
"from": {
|
||||
"blockId": "kmUzhRFzSKjkaipYNcku9S",
|
||||
"stepId": "6XgP3JoCh7Y4M8GCX9DKym"
|
||||
},
|
||||
"to": { "blockId": "bwWRAaX5m6NZyZ9jjpXmWSb" },
|
||||
"id": "ahfJ4fUuvxX2dcBMk876tf"
|
||||
},
|
||||
"dcJedLC7qsLtsmm1wbiFFc": {
|
||||
"from": {
|
||||
"blockId": "bwWRAaX5m6NZyZ9jjpXmWSb",
|
||||
"stepId": "s8n3nJajsBaYqrFeRYVvcf6"
|
||||
},
|
||||
"to": { "blockId": "baUyUnNBxZzPe1z5PqE4NkD" },
|
||||
"id": "dcJedLC7qsLtsmm1wbiFFc"
|
||||
},
|
||||
"sA5gvCVVBVYdGsdeSGF5ei": {
|
||||
"from": {
|
||||
"blockId": "baUyUnNBxZzPe1z5PqE4NkD",
|
||||
"stepId": "sugJ6xN3jFys1CjWfsxGhiJ"
|
||||
},
|
||||
"to": { "blockId": "bwkKNpJmAFCCLbZSnPnnLnR" },
|
||||
"id": "sA5gvCVVBVYdGsdeSGF5ei"
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"ahfJ4fUuvxX2dcBMk876tf",
|
||||
"dcJedLC7qsLtsmm1wbiFFc",
|
||||
"sA5gvCVVBVYdGsdeSGF5ei"
|
||||
]
|
||||
},
|
||||
"theme": {
|
||||
"chat": {
|
||||
"inputs": {
|
||||
"color": "#303235",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"placeholderColor": "#9095A0"
|
||||
},
|
||||
"buttons": { "color": "#FFFFFF", "backgroundColor": "#0042DA" },
|
||||
"hostBubbles": { "color": "#303235", "backgroundColor": "#F7F8FF" },
|
||||
"guestBubbles": { "color": "#FFFFFF", "backgroundColor": "#FF8E21" }
|
||||
},
|
||||
"general": { "font": "Open Sans", "background": { "type": "None" } }
|
||||
},
|
||||
"settings": {
|
||||
"general": { "isBrandingEnabled": true },
|
||||
"metadata": {
|
||||
"description": "Build beautiful conversational forms and embed them directly in your applications without a line of code. Triple your response rate and collect answers that has more value compared to a traditional form."
|
||||
},
|
||||
"typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 }
|
||||
},
|
||||
"publicId": null
|
||||
}
|
BIN
apps/builder/playwright/fixtures/typebots/logic/setVariable.png
Normal file
After Width: | Height: | Size: 1.2 MiB |
@ -0,0 +1,177 @@
|
||||
{
|
||||
"id": "ckylsr69q0240z31afjhedyxo",
|
||||
"createdAt": "2022-01-19T17:06:08.126Z",
|
||||
"updatedAt": "2022-01-19T17:06:08.126Z",
|
||||
"name": "My typebot",
|
||||
"ownerId": "ckylsr4fi0220z31apbinpy9d",
|
||||
"publishedTypebotId": null,
|
||||
"folderId": null,
|
||||
"webhooks": { "byId": {}, "allIds": [] },
|
||||
"blocks": {
|
||||
"byId": {
|
||||
"weeBMMXxNKwEonMfDX8Z5k": {
|
||||
"id": "weeBMMXxNKwEonMfDX8Z5k",
|
||||
"title": "Start",
|
||||
"stepIds": ["nEXiHesKXRQJhQbaWfbDVH"],
|
||||
"graphCoordinates": { "x": 0, "y": 0 }
|
||||
},
|
||||
"bg2MBdkf6y7g6WsbqAP3eAT": {
|
||||
"id": "bg2MBdkf6y7g6WsbqAP3eAT",
|
||||
"title": "Block #2",
|
||||
"graphCoordinates": { "x": 120, "y": 221 },
|
||||
"stepIds": ["sqzMjp1Ba4jTL3A6iJehC6C"]
|
||||
},
|
||||
"bj5BE1yKPzFFhvRk6cMnmsQ": {
|
||||
"id": "bj5BE1yKPzFFhvRk6cMnmsQ",
|
||||
"title": "Block #3",
|
||||
"graphCoordinates": { "x": 529, "y": 130 },
|
||||
"stepIds": ["s8zPdEj96z8EoJG2zBqgoE8"]
|
||||
},
|
||||
"bdET8zLFQbwpTaAmi4wmezE": {
|
||||
"id": "bdET8zLFQbwpTaAmi4wmezE",
|
||||
"title": "Block #4",
|
||||
"graphCoordinates": { "x": 538, "y": 386 },
|
||||
"stepIds": ["sjZ28izS5e3VjNynFKT2F7E"]
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"weeBMMXxNKwEonMfDX8Z5k",
|
||||
"bg2MBdkf6y7g6WsbqAP3eAT",
|
||||
"bj5BE1yKPzFFhvRk6cMnmsQ",
|
||||
"bdET8zLFQbwpTaAmi4wmezE"
|
||||
]
|
||||
},
|
||||
"steps": {
|
||||
"byId": {
|
||||
"nEXiHesKXRQJhQbaWfbDVH": {
|
||||
"id": "nEXiHesKXRQJhQbaWfbDVH",
|
||||
"type": "start",
|
||||
"label": "Start",
|
||||
"blockId": "weeBMMXxNKwEonMfDX8Z5k",
|
||||
"edgeId": "uh95dDpiiZdYxpPFsUqZEg"
|
||||
},
|
||||
"sqzMjp1Ba4jTL3A6iJehC6C": {
|
||||
"id": "sqzMjp1Ba4jTL3A6iJehC6C",
|
||||
"blockId": "bg2MBdkf6y7g6WsbqAP3eAT",
|
||||
"type": "choice input",
|
||||
"options": {
|
||||
"itemIds": [
|
||||
"bWrsg18ucP9cdtFKhzgHbF",
|
||||
"p7Z57shv7p79KiwAtdi8Y3",
|
||||
"wjMRa2GBBnME9bEiNi6XgP"
|
||||
]
|
||||
},
|
||||
"edgeId": "asT5shwJqDQ67qPuydR4gy"
|
||||
},
|
||||
"s8zPdEj96z8EoJG2zBqgoE8": {
|
||||
"id": "s8zPdEj96z8EoJG2zBqgoE8",
|
||||
"blockId": "bj5BE1yKPzFFhvRk6cMnmsQ",
|
||||
"type": "text",
|
||||
"content": {
|
||||
"html": "<div>I love burgers!</div>",
|
||||
"richText": [
|
||||
{ "type": "p", "children": [{ "text": "I love burgers!" }] }
|
||||
],
|
||||
"plainText": "I love burgers!"
|
||||
}
|
||||
},
|
||||
"sjZ28izS5e3VjNynFKT2F7E": {
|
||||
"id": "sjZ28izS5e3VjNynFKT2F7E",
|
||||
"blockId": "bdET8zLFQbwpTaAmi4wmezE",
|
||||
"type": "text",
|
||||
"content": {
|
||||
"html": "<div>Cool!</div>",
|
||||
"richText": [{ "type": "p", "children": [{ "text": "Cool!" }] }],
|
||||
"plainText": "Cool!"
|
||||
}
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"nEXiHesKXRQJhQbaWfbDVH",
|
||||
"sqzMjp1Ba4jTL3A6iJehC6C",
|
||||
"s8zPdEj96z8EoJG2zBqgoE8",
|
||||
"sjZ28izS5e3VjNynFKT2F7E"
|
||||
]
|
||||
},
|
||||
"choiceItems": {
|
||||
"byId": {
|
||||
"bWrsg18ucP9cdtFKhzgHbF": {
|
||||
"id": "bWrsg18ucP9cdtFKhzgHbF",
|
||||
"stepId": "sqzMjp1Ba4jTL3A6iJehC6C",
|
||||
"content": "Burgers",
|
||||
"edgeId": "jfR6AUWt9b4dhjnUHXB179"
|
||||
},
|
||||
"p7Z57shv7p79KiwAtdi8Y3": {
|
||||
"id": "p7Z57shv7p79KiwAtdi8Y3",
|
||||
"stepId": "sqzMjp1Ba4jTL3A6iJehC6C",
|
||||
"content": "Hot dogs"
|
||||
},
|
||||
"wjMRa2GBBnME9bEiNi6XgP": {
|
||||
"id": "wjMRa2GBBnME9bEiNi6XgP",
|
||||
"stepId": "sqzMjp1Ba4jTL3A6iJehC6C",
|
||||
"content": "Carpaccio"
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"bWrsg18ucP9cdtFKhzgHbF",
|
||||
"p7Z57shv7p79KiwAtdi8Y3",
|
||||
"wjMRa2GBBnME9bEiNi6XgP"
|
||||
]
|
||||
},
|
||||
"variables": { "byId": {}, "allIds": [] },
|
||||
"edges": {
|
||||
"byId": {
|
||||
"uh95dDpiiZdYxpPFsUqZEg": {
|
||||
"from": {
|
||||
"blockId": "weeBMMXxNKwEonMfDX8Z5k",
|
||||
"stepId": "nEXiHesKXRQJhQbaWfbDVH"
|
||||
},
|
||||
"to": { "blockId": "bg2MBdkf6y7g6WsbqAP3eAT" },
|
||||
"id": "uh95dDpiiZdYxpPFsUqZEg"
|
||||
},
|
||||
"jfR6AUWt9b4dhjnUHXB179": {
|
||||
"from": {
|
||||
"blockId": "bg2MBdkf6y7g6WsbqAP3eAT",
|
||||
"stepId": "sqzMjp1Ba4jTL3A6iJehC6C",
|
||||
"nodeId": "bWrsg18ucP9cdtFKhzgHbF"
|
||||
},
|
||||
"to": { "blockId": "bj5BE1yKPzFFhvRk6cMnmsQ" },
|
||||
"id": "jfR6AUWt9b4dhjnUHXB179"
|
||||
},
|
||||
"asT5shwJqDQ67qPuydR4gy": {
|
||||
"from": {
|
||||
"blockId": "bg2MBdkf6y7g6WsbqAP3eAT",
|
||||
"stepId": "sqzMjp1Ba4jTL3A6iJehC6C"
|
||||
},
|
||||
"to": { "blockId": "bdET8zLFQbwpTaAmi4wmezE" },
|
||||
"id": "asT5shwJqDQ67qPuydR4gy"
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"uh95dDpiiZdYxpPFsUqZEg",
|
||||
"jfR6AUWt9b4dhjnUHXB179",
|
||||
"asT5shwJqDQ67qPuydR4gy"
|
||||
]
|
||||
},
|
||||
"theme": {
|
||||
"chat": {
|
||||
"inputs": {
|
||||
"color": "#303235",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"placeholderColor": "#9095A0"
|
||||
},
|
||||
"buttons": { "color": "#FFFFFF", "backgroundColor": "#0042DA" },
|
||||
"hostBubbles": { "color": "#303235", "backgroundColor": "#F7F8FF" },
|
||||
"guestBubbles": { "color": "#FFFFFF", "backgroundColor": "#FF8E21" }
|
||||
},
|
||||
"general": { "font": "Open Sans", "background": { "type": "None" } }
|
||||
},
|
||||
"settings": {
|
||||
"general": { "isBrandingEnabled": true },
|
||||
"metadata": {
|
||||
"description": "Build beautiful conversational forms and embed them directly in your applications without a line of code. Triple your response rate and collect answers that has more value compared to a traditional form."
|
||||
},
|
||||
"typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 }
|
||||
},
|
||||
"publicId": null
|
||||
}
|
BIN
apps/builder/playwright/fixtures/typebots/singleChoiceTarget.png
Normal file
After Width: | Height: | Size: 1.4 MiB |
159
apps/builder/playwright/fixtures/typebots/theme.json
Normal file
@ -0,0 +1,159 @@
|
||||
{
|
||||
"id": "typebot4",
|
||||
"createdAt": "2022-01-21T07:55:14.727Z",
|
||||
"updatedAt": "2022-01-21T07:55:14.727Z",
|
||||
"name": "My typebot",
|
||||
"ownerId": "user2",
|
||||
"publishedTypebotId": null,
|
||||
"folderId": null,
|
||||
"blocks": {
|
||||
"byId": {
|
||||
"3kH2sUjVThQDWmqdoKnGk5": {
|
||||
"id": "3kH2sUjVThQDWmqdoKnGk5",
|
||||
"title": "Start",
|
||||
"stepIds": ["oxTsU2C1RX5QHuyY8qjHAM"],
|
||||
"graphCoordinates": { "x": 42, "y": 13 }
|
||||
},
|
||||
"bdFW2HHjMoEFmqHtFre9Xi8": {
|
||||
"id": "bdFW2HHjMoEFmqHtFre9Xi8",
|
||||
"title": "Block #2",
|
||||
"stepIds": ["sgkADMK25y9P9V3vjwjBaac", "ssEiEECKSFkA44dGDceHxKw"],
|
||||
"graphCoordinates": { "x": 121, "y": 227 }
|
||||
},
|
||||
"bhKHKi1SQb5woZEy1y4fNsJ": {
|
||||
"id": "bhKHKi1SQb5woZEy1y4fNsJ",
|
||||
"title": "Block #3",
|
||||
"graphCoordinates": { "x": 605, "y": 454 },
|
||||
"stepIds": ["sseUQEWCMdiZquk8EbxHYtk"]
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"3kH2sUjVThQDWmqdoKnGk5",
|
||||
"bdFW2HHjMoEFmqHtFre9Xi8",
|
||||
"bhKHKi1SQb5woZEy1y4fNsJ"
|
||||
]
|
||||
},
|
||||
"steps": {
|
||||
"byId": {
|
||||
"oxTsU2C1RX5QHuyY8qjHAM": {
|
||||
"id": "oxTsU2C1RX5QHuyY8qjHAM",
|
||||
"type": "start",
|
||||
"label": "Start",
|
||||
"edgeId": "25yX9DnQgdafpdAjfAu5Fp",
|
||||
"blockId": "3kH2sUjVThQDWmqdoKnGk5"
|
||||
},
|
||||
"sgkADMK25y9P9V3vjwjBaac": {
|
||||
"id": "sgkADMK25y9P9V3vjwjBaac",
|
||||
"type": "text",
|
||||
"blockId": "bdFW2HHjMoEFmqHtFre9Xi8",
|
||||
"content": {
|
||||
"html": "<div>Ready?</div>",
|
||||
"richText": [{ "type": "p", "children": [{ "text": "Ready?" }] }],
|
||||
"plainText": "Ready?"
|
||||
}
|
||||
},
|
||||
"ssEiEECKSFkA44dGDceHxKw": {
|
||||
"id": "ssEiEECKSFkA44dGDceHxKw",
|
||||
"type": "choice input",
|
||||
"edgeId": "6e4Sbp8pGTvBQYtCk2qXbN",
|
||||
"blockId": "bdFW2HHjMoEFmqHtFre9Xi8",
|
||||
"options": { "itemIds": ["q69Ex7LacPrH9QUMeosRnB"] }
|
||||
},
|
||||
"sseUQEWCMdiZquk8EbxHYtk": {
|
||||
"id": "sseUQEWCMdiZquk8EbxHYtk",
|
||||
"blockId": "bhKHKi1SQb5woZEy1y4fNsJ",
|
||||
"type": "text input"
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"oxTsU2C1RX5QHuyY8qjHAM",
|
||||
"sgkADMK25y9P9V3vjwjBaac",
|
||||
"ssEiEECKSFkA44dGDceHxKw",
|
||||
"sseUQEWCMdiZquk8EbxHYtk"
|
||||
]
|
||||
},
|
||||
"choiceItems": {
|
||||
"byId": {
|
||||
"q69Ex7LacPrH9QUMeosRnB": {
|
||||
"id": "q69Ex7LacPrH9QUMeosRnB",
|
||||
"stepId": "ssEiEECKSFkA44dGDceHxKw",
|
||||
"content": "Go"
|
||||
}
|
||||
},
|
||||
"allIds": ["q69Ex7LacPrH9QUMeosRnB"]
|
||||
},
|
||||
"variables": {
|
||||
"byId": {
|
||||
"4tvkRmf32wiTsXrYoqyhfr": {
|
||||
"id": "4tvkRmf32wiTsXrYoqyhfr",
|
||||
"name": "secret 2"
|
||||
},
|
||||
"jEg1FvkCU5S5owNAxXFsHL": {
|
||||
"id": "jEg1FvkCU5S5owNAxXFsHL",
|
||||
"name": "secret 3"
|
||||
},
|
||||
"oASkBtoLqkYNqeakcjZH4L": {
|
||||
"id": "oASkBtoLqkYNqeakcjZH4L",
|
||||
"name": "secret 1"
|
||||
},
|
||||
"rEoE1ehHzgx8X3d3UPGDHg": {
|
||||
"id": "rEoE1ehHzgx8X3d3UPGDHg",
|
||||
"name": "secret 4"
|
||||
}
|
||||
},
|
||||
"allIds": [
|
||||
"oASkBtoLqkYNqeakcjZH4L",
|
||||
"4tvkRmf32wiTsXrYoqyhfr",
|
||||
"jEg1FvkCU5S5owNAxXFsHL",
|
||||
"rEoE1ehHzgx8X3d3UPGDHg"
|
||||
]
|
||||
},
|
||||
"webhooks": {
|
||||
"byId": {
|
||||
"4h4Kk3Q1qGy7gFzpZtWVpU": { "id": "4h4Kk3Q1qGy7gFzpZtWVpU", "url": "" }
|
||||
},
|
||||
"allIds": ["4h4Kk3Q1qGy7gFzpZtWVpU"]
|
||||
},
|
||||
"edges": {
|
||||
"byId": {
|
||||
"25yX9DnQgdafpdAjfAu5Fp": {
|
||||
"id": "25yX9DnQgdafpdAjfAu5Fp",
|
||||
"to": { "blockId": "bdFW2HHjMoEFmqHtFre9Xi8" },
|
||||
"from": {
|
||||
"stepId": "oxTsU2C1RX5QHuyY8qjHAM",
|
||||
"blockId": "3kH2sUjVThQDWmqdoKnGk5"
|
||||
}
|
||||
},
|
||||
"6e4Sbp8pGTvBQYtCk2qXbN": {
|
||||
"from": {
|
||||
"blockId": "bdFW2HHjMoEFmqHtFre9Xi8",
|
||||
"stepId": "ssEiEECKSFkA44dGDceHxKw"
|
||||
},
|
||||
"to": { "blockId": "bhKHKi1SQb5woZEy1y4fNsJ" },
|
||||
"id": "6e4Sbp8pGTvBQYtCk2qXbN"
|
||||
}
|
||||
},
|
||||
"allIds": ["25yX9DnQgdafpdAjfAu5Fp", "6e4Sbp8pGTvBQYtCk2qXbN"]
|
||||
},
|
||||
"theme": {
|
||||
"chat": {
|
||||
"inputs": {
|
||||
"color": "#303235",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"placeholderColor": "#9095A0"
|
||||
},
|
||||
"buttons": { "color": "#FFFFFF", "backgroundColor": "#0042DA" },
|
||||
"hostBubbles": { "color": "#303235", "backgroundColor": "#F7F8FF" },
|
||||
"guestBubbles": { "color": "#FFFFFF", "backgroundColor": "#FF8E21" }
|
||||
},
|
||||
"general": { "font": "Open Sans", "background": { "type": "None" } }
|
||||
},
|
||||
"settings": {
|
||||
"general": { "isBrandingEnabled": true },
|
||||
"metadata": {
|
||||
"description": "Build beautiful conversational forms and embed them directly in your applications without a line of code. Triple your response rate and collect answers that has more value compared to a traditional form."
|
||||
},
|
||||
"typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 }
|
||||
},
|
||||
"publicId": null
|
||||
}
|
31
apps/builder/playwright/global-setup.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { chromium, FullConfig, Page } from '@playwright/test'
|
||||
import { setupDatabase, teardownDatabase, user } from './services/database'
|
||||
|
||||
async function globalSetup(config: FullConfig) {
|
||||
const { baseURL } = config.projects[0].use
|
||||
if (!baseURL) throw new Error('baseURL is missing')
|
||||
|
||||
await teardownDatabase()
|
||||
await setupDatabase()
|
||||
|
||||
// Skip auth if debugging
|
||||
if (process.env.PWDEBUG === '1') return
|
||||
|
||||
const browser = await chromium.launch()
|
||||
const page = await browser.newPage()
|
||||
await signIn(page, user.email)
|
||||
await page.context().storageState({
|
||||
path: './playwright/authenticatedState.json',
|
||||
})
|
||||
}
|
||||
|
||||
const signIn = async (page: Page, email: string) => {
|
||||
await page.goto('http://localhost:3000/api/auth/signin')
|
||||
await page.fill('[placeholder="credentials\\@email\\.com"]', email)
|
||||
await Promise.all([
|
||||
page.waitForNavigation({ url: 'http://localhost:3000/typebots' }),
|
||||
page.press('[placeholder="credentials\\@email\\.com"]', 'Enter'),
|
||||
])
|
||||
}
|
||||
|
||||
export default globalSetup
|
5
apps/builder/playwright/services/browser.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export const refreshUser = async () => {
|
||||
await fetch('/api/auth/session?update')
|
||||
const event = new Event('visibilitychange')
|
||||
document.dispatchEvent(event)
|
||||
}
|
230
apps/builder/playwright/services/database.ts
Normal file
@ -0,0 +1,230 @@
|
||||
import {
|
||||
defaultSettings,
|
||||
defaultTheme,
|
||||
PublicTypebot,
|
||||
Step,
|
||||
Typebot,
|
||||
} from 'models'
|
||||
import { CredentialsType, DashboardFolder, Plan, PrismaClient, User } from 'db'
|
||||
import { readFileSync } from 'fs'
|
||||
|
||||
export const user = { id: 'user1', email: 'test1@gmail.com' }
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
export const teardownDatabase = async () => prisma.user.deleteMany()
|
||||
|
||||
export const setupDatabase = async () => {
|
||||
await createUsers()
|
||||
return createCredentials()
|
||||
}
|
||||
|
||||
export const createTypebots = async (partialTypebots: Partial<Typebot>[]) => {
|
||||
await prisma.typebot.createMany({
|
||||
data: partialTypebots.map(parseTestTypebot) as any[],
|
||||
})
|
||||
return prisma.publicTypebot.createMany({
|
||||
data: partialTypebots.map((t) =>
|
||||
parseTypebotToPublicTypebot(t.id + '-public', parseTestTypebot(t))
|
||||
) as any[],
|
||||
})
|
||||
}
|
||||
|
||||
export const createFolders = (partialFolders: Partial<DashboardFolder>[]) =>
|
||||
prisma.dashboardFolder.createMany({
|
||||
data: partialFolders.map((folder) => ({
|
||||
ownerId: user.id,
|
||||
name: 'Folder #1',
|
||||
id: 'folder',
|
||||
...folder,
|
||||
})),
|
||||
})
|
||||
|
||||
const createUsers = () =>
|
||||
prisma.user.create({
|
||||
data: {
|
||||
...user,
|
||||
emailVerified: new Date(),
|
||||
plan: Plan.FREE,
|
||||
stripeId: 'stripe-test2',
|
||||
},
|
||||
})
|
||||
|
||||
const createCredentials = () => {
|
||||
if (!process.env.GOOGLE_REFRESH_TOKEN_TEST)
|
||||
console.warn(
|
||||
'GOOGLE_REFRESH_TOKEN_TEST env var is missing. It is required to run Google Sheets tests'
|
||||
)
|
||||
return prisma.credentials.createMany({
|
||||
data: [
|
||||
{
|
||||
name: 'test2@gmail.com',
|
||||
ownerId: user.id,
|
||||
type: CredentialsType.GOOGLE_SHEETS,
|
||||
data: {
|
||||
expiry_date: 1642441058842,
|
||||
access_token:
|
||||
'ya29.A0ARrdaM--PV_87ebjywDJpXKb77NBFJl16meVUapYdfNv6W6ZzqqC47fNaPaRjbDbOIIcp6f49cMaX5ndK9TAFnKwlVqz3nrK9nLKqgyDIhYsIq47smcAIZkK56SWPx3X3DwAFqRu2UPojpd2upWwo-3uJrod',
|
||||
refresh_token: process.env.GOOGLE_REFRESH_TOKEN_TEST,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
export const updateUser = (data: Partial<User>) =>
|
||||
prisma.user.update({ data, where: { id: user.id } })
|
||||
|
||||
export const createResults = async ({ typebotId }: { typebotId: string }) => {
|
||||
await prisma.result.createMany({
|
||||
data: [
|
||||
...Array.from(Array(200)).map((_, idx) => {
|
||||
const today = new Date()
|
||||
return {
|
||||
id: `result${idx}`,
|
||||
typebotId,
|
||||
createdAt: new Date(
|
||||
today.setTime(today.getTime() + 1000 * 60 * 60 * 24 * idx)
|
||||
),
|
||||
isCompleted: false,
|
||||
}
|
||||
}),
|
||||
],
|
||||
})
|
||||
return createAnswers()
|
||||
}
|
||||
|
||||
const createAnswers = () => {
|
||||
return prisma.answer.createMany({
|
||||
data: [
|
||||
...Array.from(Array(200)).map((_, idx) => ({
|
||||
resultId: `result${idx}`,
|
||||
content: `content${idx}`,
|
||||
stepId: 'step1',
|
||||
blockId: 'block1',
|
||||
})),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
const parseTypebotToPublicTypebot = (
|
||||
id: string,
|
||||
typebot: Typebot
|
||||
): PublicTypebot => ({
|
||||
id,
|
||||
blocks: typebot.blocks,
|
||||
steps: typebot.steps,
|
||||
name: typebot.name,
|
||||
typebotId: typebot.id,
|
||||
theme: typebot.theme,
|
||||
settings: typebot.settings,
|
||||
publicId: typebot.publicId,
|
||||
choiceItems: typebot.choiceItems,
|
||||
variables: typebot.variables,
|
||||
edges: typebot.edges,
|
||||
})
|
||||
|
||||
export const loadRawTypebotInDatabase = (typebot: Typebot) =>
|
||||
prisma.typebot.create({
|
||||
data: {
|
||||
...typebot,
|
||||
id: 'typebot4',
|
||||
ownerId: user.id,
|
||||
} as any,
|
||||
})
|
||||
|
||||
const parseTestTypebot = (partialTypebot: Partial<Typebot>): Typebot => ({
|
||||
id: partialTypebot.id ?? 'typebot',
|
||||
folderId: null,
|
||||
name: 'My typebot',
|
||||
ownerId: user.id,
|
||||
theme: defaultTheme,
|
||||
settings: defaultSettings,
|
||||
createdAt: new Date(),
|
||||
choiceItems: partialTypebot.choiceItems ?? {
|
||||
byId: {
|
||||
choice1: {
|
||||
id: 'choice1',
|
||||
stepId: 'step1',
|
||||
},
|
||||
},
|
||||
allIds: ['choice1'],
|
||||
},
|
||||
publicId: null,
|
||||
publishedTypebotId: null,
|
||||
updatedAt: new Date(),
|
||||
variables: { byId: {}, allIds: [] },
|
||||
webhooks: { byId: {}, allIds: [] },
|
||||
edges: {
|
||||
byId: {
|
||||
edge1: {
|
||||
id: 'edge1',
|
||||
from: { blockId: 'block0', stepId: 'step0' },
|
||||
to: { blockId: 'block1' },
|
||||
},
|
||||
},
|
||||
allIds: ['edge1'],
|
||||
},
|
||||
...partialTypebot,
|
||||
blocks: {
|
||||
byId: {
|
||||
block0: {
|
||||
id: 'block0',
|
||||
title: 'Block #0',
|
||||
stepIds: ['step0'],
|
||||
graphCoordinates: { x: 0, y: 0 },
|
||||
},
|
||||
...partialTypebot.blocks?.byId,
|
||||
},
|
||||
allIds: ['block0', ...(partialTypebot.blocks?.allIds ?? [])],
|
||||
},
|
||||
steps: {
|
||||
byId: {
|
||||
step0: {
|
||||
id: 'step0',
|
||||
type: 'start',
|
||||
blockId: 'block0',
|
||||
label: 'Start',
|
||||
edgeId: 'edge1',
|
||||
},
|
||||
...partialTypebot.steps?.byId,
|
||||
},
|
||||
allIds: ['step0', ...(partialTypebot.steps?.allIds ?? [])],
|
||||
},
|
||||
})
|
||||
|
||||
export const parseDefaultBlockWithStep = (
|
||||
step: Partial<Step>
|
||||
): Pick<Typebot, 'blocks' | 'steps'> => ({
|
||||
blocks: {
|
||||
byId: {
|
||||
block1: {
|
||||
graphCoordinates: { x: 200, y: 200 },
|
||||
id: 'block1',
|
||||
stepIds: ['step1'],
|
||||
title: 'Block #1',
|
||||
},
|
||||
},
|
||||
allIds: ['block1'],
|
||||
},
|
||||
steps: {
|
||||
byId: {
|
||||
step1: {
|
||||
id: 'step1',
|
||||
blockId: 'block1',
|
||||
...step,
|
||||
} as Step,
|
||||
},
|
||||
allIds: ['step1'],
|
||||
},
|
||||
})
|
||||
|
||||
export const importTypebotInDatabase = (
|
||||
path: string,
|
||||
updates?: Partial<Typebot>
|
||||
) => {
|
||||
const typebot: Typebot = JSON.parse(readFileSync(path).toString())
|
||||
return prisma.typebot.create({
|
||||
data: { ...typebot, ...updates, ownerId: user.id } as any,
|
||||
})
|
||||
}
|
7
apps/builder/playwright/services/selectorUtils.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { Page } from '@playwright/test'
|
||||
|
||||
export const deleteButtonInConfirmDialog = (page: Page) =>
|
||||
page.locator('section[role="alertdialog"] button:has-text("Delete")')
|
||||
|
||||
export const typebotViewer = (page: Page) =>
|
||||
page.frameLocator('#typebot-iframe')
|
51
apps/builder/playwright/tests/account.spec.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { refreshUser } from '../services/browser'
|
||||
import { Plan } from 'db'
|
||||
import path from 'path'
|
||||
import { updateUser, user } from '../services/database'
|
||||
|
||||
test.describe('Account page', () => {
|
||||
test('should edit user info properly', async ({ page }) => {
|
||||
await page.goto('/account')
|
||||
const saveButton = page.locator('button:has-text("Save")')
|
||||
await expect(saveButton).toBeHidden()
|
||||
await expect(
|
||||
page.locator('input[type="email"]').getAttribute('disabled')
|
||||
).toBeDefined()
|
||||
await page.fill('#name', 'John Doe')
|
||||
expect(saveButton).toBeVisible()
|
||||
const avatarImg = page.locator('img')
|
||||
await expect(page.locator('text=JD')).toBeVisible()
|
||||
await expect(avatarImg).toBeHidden()
|
||||
await page.setInputFiles(
|
||||
'input[type="file"]',
|
||||
path.join(__dirname, '../fixtures/avatar.jpg')
|
||||
)
|
||||
await expect(avatarImg).toHaveAttribute(
|
||||
'src',
|
||||
new RegExp(
|
||||
`https://s3.eu-west-3.amazonaws.com/typebot/users/${user.id}/avatar`,
|
||||
'gm'
|
||||
)
|
||||
)
|
||||
await saveButton.click()
|
||||
await expect(saveButton).toBeHidden()
|
||||
})
|
||||
|
||||
test('should display valid plans', async ({ page }) => {
|
||||
await updateUser({ plan: Plan.FREE, stripeId: null })
|
||||
await page.goto('/account')
|
||||
await expect(page.locator('text=Free plan')).toBeVisible()
|
||||
await page.evaluate(refreshUser)
|
||||
await page.reload()
|
||||
const manageSubscriptionButton = page.locator(
|
||||
'a:has-text("Manage my subscription")'
|
||||
)
|
||||
await expect(manageSubscriptionButton).toBeHidden()
|
||||
await updateUser({ plan: Plan.PRO, stripeId: 'stripeId' })
|
||||
await page.evaluate(refreshUser)
|
||||
await page.reload()
|
||||
await expect(page.locator('text=Pro plan')).toBeVisible()
|
||||
await expect(manageSubscriptionButton).toBeVisible()
|
||||
})
|
||||
})
|
113
apps/builder/playwright/tests/bubbles/image.spec.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import {
|
||||
createTypebots,
|
||||
parseDefaultBlockWithStep,
|
||||
} from '../../services/database'
|
||||
import { BubbleStepType, defaultImageBubbleContent } from 'models'
|
||||
import { typebotViewer } from '../../services/selectorUtils'
|
||||
import path from 'path'
|
||||
|
||||
const unsplashImageSrc =
|
||||
'https://images.unsplash.com/photo-1504297050568-910d24c426d3?ixlib=rb-1.2.1&ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1287&q=80'
|
||||
|
||||
test.describe.parallel('Image bubble step', () => {
|
||||
test.describe('Content settings', () => {
|
||||
test('should upload image file correctly', async ({ page }) => {
|
||||
const typebotId = 'image-bubble-step-image-upload'
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: BubbleStepType.IMAGE,
|
||||
content: defaultImageBubbleContent,
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
|
||||
await page.click('text=Click to edit...')
|
||||
await page.setInputFiles(
|
||||
'input[type="file"]',
|
||||
path.join(__dirname, '../../fixtures/avatar.jpg')
|
||||
)
|
||||
await expect(page.locator('img')).toHaveAttribute(
|
||||
'src',
|
||||
new RegExp(
|
||||
`https://s3.eu-west-3.amazonaws.com/typebot/typebots/${typebotId}/avatar.jpg`,
|
||||
'gm'
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
test('should import image link correctly', async ({ page }) => {
|
||||
const typebotId = 'image-bubble-step-image-link'
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: BubbleStepType.IMAGE,
|
||||
content: defaultImageBubbleContent,
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
|
||||
await page.click('text=Click to edit...')
|
||||
await page.click('text=Embed link')
|
||||
await page.fill(
|
||||
'input[placeholder="Paste the image link..."]',
|
||||
unsplashImageSrc
|
||||
)
|
||||
await expect(page.locator('img')).toHaveAttribute('src', unsplashImageSrc)
|
||||
})
|
||||
|
||||
test('should import gifs correctly', async ({ page }) => {
|
||||
const typebotId = 'image-bubble-step-gifs'
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: BubbleStepType.IMAGE,
|
||||
content: defaultImageBubbleContent,
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
|
||||
await page.click('text=Click to edit...')
|
||||
await page.click('text=Giphy')
|
||||
await page.click('img >> nth=3')
|
||||
await expect(page.locator('img[alt="Step image"]')).toHaveAttribute(
|
||||
'src',
|
||||
new RegExp('giphy.com/media', 'gm')
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Preview', () => {
|
||||
test('should display correctly', async ({ page }) => {
|
||||
const typebotId = 'image-bubble-step-preview'
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: BubbleStepType.IMAGE,
|
||||
content: {
|
||||
url: unsplashImageSrc,
|
||||
},
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
await page.click('text=Preview')
|
||||
await expect(typebotViewer(page).locator('img')).toHaveAttribute(
|
||||
'src',
|
||||
unsplashImageSrc
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
55
apps/builder/playwright/tests/bubbles/text.spec.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import {
|
||||
createTypebots,
|
||||
parseDefaultBlockWithStep,
|
||||
} from '../../services/database'
|
||||
import { BubbleStepType, defaultTextBubbleContent } from 'models'
|
||||
import { typebotViewer } from '../../services/selectorUtils'
|
||||
|
||||
const typebotId = 'text-bubble-step'
|
||||
|
||||
test.describe('Text bubble step', () => {
|
||||
test('rich text features should work', async ({ page }) => {
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: BubbleStepType.TEXT,
|
||||
content: defaultTextBubbleContent,
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
|
||||
await page.click('[data-testid="bold-button"]')
|
||||
await page.type('div[role="textbox"]', 'Bold text')
|
||||
await page.press('div[role="textbox"]', 'Enter')
|
||||
|
||||
await page.click('[data-testid="bold-button"]')
|
||||
await page.click('[data-testid="italic-button"]')
|
||||
await page.type('div[role="textbox"]', 'Italic text')
|
||||
await page.press('div[role="textbox"]', 'Enter')
|
||||
|
||||
await page.click('[data-testid="underline-button"]')
|
||||
await page.click('[data-testid="italic-button"]')
|
||||
await page.type('div[role="textbox"]', 'Underlined text')
|
||||
await page.press('div[role="textbox"]', 'Enter')
|
||||
|
||||
await page.click('[data-testid="bold-button"]')
|
||||
await page.click('[data-testid="italic-button"]')
|
||||
await page.type('div[role="textbox"]', 'Everything text')
|
||||
await page.press('div[role="textbox"]', 'Enter')
|
||||
|
||||
await page.click('text=Preview')
|
||||
await expect(
|
||||
typebotViewer(page).locator('span.slate-bold >> nth=0')
|
||||
).toHaveText('Bold text')
|
||||
await expect(
|
||||
typebotViewer(page).locator('span.slate-italic >> nth=0')
|
||||
).toHaveText('Italic text')
|
||||
await expect(
|
||||
typebotViewer(page).locator('span.slate-underline >> nth=0')
|
||||
).toHaveText('Underlined text')
|
||||
})
|
||||
})
|
114
apps/builder/playwright/tests/bubbles/video.spec.ts
Normal file
@ -0,0 +1,114 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import {
|
||||
createTypebots,
|
||||
parseDefaultBlockWithStep,
|
||||
} from '../../services/database'
|
||||
import {
|
||||
BubbleStepType,
|
||||
defaultVideoBubbleContent,
|
||||
VideoBubbleContentType,
|
||||
} from 'models'
|
||||
import { typebotViewer } from '../../services/selectorUtils'
|
||||
|
||||
const videoSrc =
|
||||
'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4'
|
||||
const youtubeVideoSrc = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
|
||||
const vimeoVideoSrc = 'https://vimeo.com/649301125'
|
||||
|
||||
test.describe.parallel('Video bubble step', () => {
|
||||
test.describe('Content settings', () => {
|
||||
test('should import video url correctly', async ({ page }) => {
|
||||
const typebotId = 'video-bubble-step-link'
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: BubbleStepType.VIDEO,
|
||||
content: defaultVideoBubbleContent,
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
|
||||
await page.click('text=Click to edit...')
|
||||
await page.fill('input[placeholder="Paste the video link..."]', videoSrc)
|
||||
await expect(page.locator('video > source')).toHaveAttribute(
|
||||
'src',
|
||||
videoSrc
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Preview', () => {
|
||||
test('should display video correctly', async ({ page }) => {
|
||||
const typebotId = 'image-bubble-step-preview-video'
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: BubbleStepType.VIDEO,
|
||||
content: {
|
||||
type: VideoBubbleContentType.URL,
|
||||
url: videoSrc,
|
||||
},
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
await page.click('text=Preview')
|
||||
await expect(
|
||||
typebotViewer(page).locator('video > source')
|
||||
).toHaveAttribute('src', videoSrc)
|
||||
})
|
||||
|
||||
test('should display youtube video correctly', async ({ page }) => {
|
||||
const typebotId = 'image-bubble-step-preview-youtube'
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: BubbleStepType.VIDEO,
|
||||
content: {
|
||||
type: VideoBubbleContentType.YOUTUBE,
|
||||
url: youtubeVideoSrc,
|
||||
id: 'dQw4w9WgXcQ',
|
||||
},
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
await page.click('text=Preview')
|
||||
await expect(typebotViewer(page).locator('iframe')).toHaveAttribute(
|
||||
'src',
|
||||
'https://www.youtube.com/embed/dQw4w9WgXcQ'
|
||||
)
|
||||
})
|
||||
|
||||
test('should display vimeo video correctly', async ({ page }) => {
|
||||
const typebotId = 'image-bubble-step-preview-vimeo'
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: BubbleStepType.VIDEO,
|
||||
content: {
|
||||
type: VideoBubbleContentType.VIMEO,
|
||||
url: vimeoVideoSrc,
|
||||
id: '649301125',
|
||||
},
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
await page.click('text=Preview')
|
||||
await expect(typebotViewer(page).locator('iframe')).toHaveAttribute(
|
||||
'src',
|
||||
'https://player.vimeo.com/video/649301125'
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
80
apps/builder/playwright/tests/dashboard.spec.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import test, { expect, Page } from '@playwright/test'
|
||||
import { createFolders, createTypebots } from '../services/database'
|
||||
import { deleteButtonInConfirmDialog } from '../services/selectorUtils'
|
||||
|
||||
test.describe('Dashboard page', () => {
|
||||
test('folders navigation should work', async ({ page }) => {
|
||||
await page.goto('/typebots')
|
||||
const createFolderButton = page.locator(
|
||||
'button:has-text("Create a folder")'
|
||||
)
|
||||
await expect(createFolderButton).not.toBeDisabled()
|
||||
await createFolderButton.click()
|
||||
await page.click('text="New folder"')
|
||||
await page.fill('input[value="New folder"]', 'My folder #1')
|
||||
await page.press('input[value="My folder #1"]', 'Enter')
|
||||
await waitForNextApiCall(page)
|
||||
await page.click('li:has-text("My folder #1")')
|
||||
await expect(page.locator('h1:has-text("My folder #1")')).toBeVisible()
|
||||
await createFolderButton.click()
|
||||
await page.click('text="New folder"')
|
||||
await page.fill('input', 'My folder #2')
|
||||
await page.press('input', 'Enter')
|
||||
|
||||
await page.click('li:has-text("My folder #2")')
|
||||
await expect(page.locator('h1 >> text="My folder #2"')).toBeVisible()
|
||||
|
||||
await page.click('text="Back"')
|
||||
await expect(page.locator('span >> text="My folder #2"')).toBeVisible()
|
||||
|
||||
await page.click('text="Back"')
|
||||
await expect(page.locator('span >> text=My folder #1')).toBeVisible()
|
||||
})
|
||||
|
||||
test('folders and typebots should be deletable', async ({ page }) => {
|
||||
await createFolders([
|
||||
{ id: 'folder1', name: 'Folder #1' },
|
||||
{ id: 'folder2', name: 'Folder #2' },
|
||||
])
|
||||
await createTypebots([{ id: 'deletable-typebot', name: 'Typebot #1' }])
|
||||
await page.goto('/typebots')
|
||||
await page.click('button[aria-label="Show Folder #1 menu"]')
|
||||
await page.click('li:has-text("Folder #1") >> button:has-text("Delete")')
|
||||
await deleteButtonInConfirmDialog(page).click()
|
||||
await expect(page.locator('span >> text="Folder #1"')).not.toBeVisible()
|
||||
await page.click('button[aria-label="Show Typebot #1 menu"]')
|
||||
await page.click('li:has-text("Typebot #1") >> button:has-text("Delete")')
|
||||
await deleteButtonInConfirmDialog(page).click()
|
||||
await expect(page.locator('span >> text="Typebot #1"')).not.toBeVisible()
|
||||
})
|
||||
|
||||
test('folders and typebots should be movable', async ({ page }) => {
|
||||
await createFolders([{ id: 'droppable-folder', name: 'Droppable folder' }])
|
||||
await createTypebots([
|
||||
{ id: 'draggable-typebot', name: 'Draggable typebot' },
|
||||
])
|
||||
await page.goto('/typebots')
|
||||
const typebotButton = page.locator('li:has-text("Draggable typebot")')
|
||||
const folderButton = page.locator('li:has-text("Droppable folder")')
|
||||
await page.dragAndDrop(
|
||||
'li:has-text("Draggable typebot")',
|
||||
'li:has-text("Droppable folder")'
|
||||
)
|
||||
await waitForNextApiCall(page)
|
||||
await expect(typebotButton).toBeHidden()
|
||||
await folderButton.click()
|
||||
await expect(page).toHaveURL(/folders\/droppable-folder/)
|
||||
await expect(typebotButton).toBeVisible()
|
||||
await page.dragAndDrop(
|
||||
'li:has-text("Draggable typebot")',
|
||||
'a:has-text("Back")'
|
||||
)
|
||||
await waitForNextApiCall(page)
|
||||
await expect(typebotButton).toBeHidden()
|
||||
await page.click('a:has-text("Back")')
|
||||
await expect(typebotButton).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
const waitForNextApiCall = (page: Page, path?: string) =>
|
||||
page.waitForResponse((resp) => resp.url().includes(path ?? '/api'))
|
65
apps/builder/playwright/tests/inputs/buttons.spec.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import {
|
||||
createTypebots,
|
||||
parseDefaultBlockWithStep,
|
||||
} from '../../services/database'
|
||||
import { defaultChoiceInputOptions, InputStepType } from 'models'
|
||||
import { typebotViewer } from '../../services/selectorUtils'
|
||||
|
||||
const typebotId = 'buttons-input-step'
|
||||
|
||||
test.describe.parallel('Buttons input step', () => {
|
||||
test('can edit button items', async ({ page }) => {
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: InputStepType.CHOICE,
|
||||
options: { ...defaultChoiceInputOptions, itemIds: ['choice1'] },
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
await page.fill('input[value="Click to edit"]', 'Item 1')
|
||||
await page.press('input[value="Item 1"]', 'Enter')
|
||||
await page.locator('text=Item 1').hover()
|
||||
await page.click('[aria-label="Add item"]')
|
||||
await page.fill('input[value="Click to edit"]', 'Item 2')
|
||||
await page.press('input[value="Item 2"]', 'Enter')
|
||||
await page.locator('text=Item 2').hover()
|
||||
await page.click('[aria-label="Add item"]')
|
||||
await page.fill('input[value="Click to edit"]', 'Item 3')
|
||||
await page.press('input[value="Item 3"]', 'Enter')
|
||||
await page.click('text=Item 2', { button: 'right' })
|
||||
await page.click('text=Delete')
|
||||
await expect(page.locator('text=Item 2')).toBeHidden()
|
||||
|
||||
await page.click('text=Preview')
|
||||
const item3Button = typebotViewer(page).locator('button >> text=Item 3')
|
||||
await item3Button.click()
|
||||
await expect(item3Button).toBeHidden()
|
||||
await expect(typebotViewer(page).locator('text=Item 3')).toBeVisible()
|
||||
await page.click('button[aria-label="Close"]')
|
||||
|
||||
await page.click('[data-testid="step1-icon"]')
|
||||
await page.click('text=Multiple choice?')
|
||||
await page.fill('#button', 'Go')
|
||||
await page.click('[data-testid="step1-icon"]')
|
||||
|
||||
await page.locator('text=Item 1').hover()
|
||||
await page.click('[aria-label="Add item"]')
|
||||
await page.fill('input[value="Click to edit"]', 'Item 2')
|
||||
await page.press('input[value="Item 2"]', 'Enter')
|
||||
|
||||
await page.click('text=Preview')
|
||||
|
||||
await typebotViewer(page).locator('button >> text="Item 3"').click()
|
||||
await typebotViewer(page).locator('button >> text="Item 1"').click()
|
||||
await typebotViewer(page).locator('text=Go').click()
|
||||
|
||||
await expect(
|
||||
typebotViewer(page).locator('text="Item 3, Item 1"')
|
||||
).toBeVisible()
|
||||
})
|
||||
})
|
46
apps/builder/playwright/tests/inputs/date.spec.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import {
|
||||
createTypebots,
|
||||
parseDefaultBlockWithStep,
|
||||
} from '../../services/database'
|
||||
import { defaultDateInputOptions, InputStepType } from 'models'
|
||||
import { typebotViewer } from '../../services/selectorUtils'
|
||||
|
||||
const typebotId = 'date-input-step'
|
||||
|
||||
test.describe('Date input step', () => {
|
||||
test('options should work', async ({ page }) => {
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: InputStepType.DATE,
|
||||
options: defaultDateInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
|
||||
await page.click('text=Preview')
|
||||
await expect(
|
||||
typebotViewer(page).locator('[data-testid="from-date"]')
|
||||
).toHaveAttribute('type', 'date')
|
||||
await expect(typebotViewer(page).locator(`button`)).toBeDisabled()
|
||||
|
||||
await page.click(`text=Pick a date...`)
|
||||
await page.click('text=Is range?')
|
||||
await page.click('text=With time?')
|
||||
await page.fill('#from', 'Previous:')
|
||||
await page.fill('#to', 'After:')
|
||||
await page.fill('#button', 'Go')
|
||||
|
||||
await page.click('text=Restart')
|
||||
await expect(
|
||||
typebotViewer(page).locator(`[data-testid="from-date"]`)
|
||||
).toHaveAttribute('type', 'datetime-local')
|
||||
await expect(
|
||||
typebotViewer(page).locator(`[data-testid="to-date"]`)
|
||||
).toHaveAttribute('type', 'datetime-local')
|
||||
})
|
||||
})
|
43
apps/builder/playwright/tests/inputs/email.spec.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import {
|
||||
createTypebots,
|
||||
parseDefaultBlockWithStep,
|
||||
} from '../../services/database'
|
||||
import { defaultEmailInputOptions, InputStepType } from 'models'
|
||||
import { typebotViewer } from '../../services/selectorUtils'
|
||||
|
||||
const typebotId = 'email-input-step'
|
||||
|
||||
test.describe('Email input step', () => {
|
||||
test('options should work', async ({ page }) => {
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: InputStepType.EMAIL,
|
||||
options: defaultEmailInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
|
||||
await page.click('text=Preview')
|
||||
await expect(
|
||||
typebotViewer(page).locator(
|
||||
`input[placeholder="${defaultEmailInputOptions.labels.placeholder}"]`
|
||||
)
|
||||
).toHaveAttribute('type', 'email')
|
||||
await expect(typebotViewer(page).locator(`button`)).toBeDisabled()
|
||||
|
||||
await page.click(`text=${defaultEmailInputOptions.labels.placeholder}`)
|
||||
await page.fill('#placeholder', 'Your email...')
|
||||
await expect(page.locator('text=Your email...')).toBeVisible()
|
||||
await page.fill('#button', 'Go')
|
||||
|
||||
await page.click('text=Restart')
|
||||
await expect(
|
||||
typebotViewer(page).locator(`input[placeholder="Your email..."]`)
|
||||
).toBeVisible()
|
||||
})
|
||||
})
|
53
apps/builder/playwright/tests/inputs/number.spec.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import {
|
||||
createTypebots,
|
||||
parseDefaultBlockWithStep,
|
||||
} from '../../services/database'
|
||||
import { defaultNumberInputOptions, InputStepType } from 'models'
|
||||
import { typebotViewer } from '../../services/selectorUtils'
|
||||
|
||||
const typebotId = 'number-input-step'
|
||||
|
||||
test.describe('Number input step', () => {
|
||||
test('options should work', async ({ page }) => {
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: InputStepType.NUMBER,
|
||||
options: defaultNumberInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
|
||||
await page.click('text=Preview')
|
||||
await expect(
|
||||
typebotViewer(page).locator(
|
||||
`input[placeholder="${defaultNumberInputOptions.labels.placeholder}"]`
|
||||
)
|
||||
).toHaveAttribute('type', 'number')
|
||||
await expect(typebotViewer(page).locator(`button`)).toBeDisabled()
|
||||
|
||||
await page.click(`text=${defaultNumberInputOptions.labels.placeholder}`)
|
||||
await page.fill('#placeholder', 'Your number...')
|
||||
await expect(page.locator('text=Your number...')).toBeVisible()
|
||||
await page.fill('#button', 'Go')
|
||||
await page.fill('[role="spinbutton"] >> nth=0', '0')
|
||||
await page.fill('[role="spinbutton"] >> nth=1', '100')
|
||||
await page.fill('[role="spinbutton"] >> nth=2', '10')
|
||||
|
||||
await page.click('text=Restart')
|
||||
const input = typebotViewer(page).locator(
|
||||
`input[placeholder="Your number..."]`
|
||||
)
|
||||
await input.fill('-1')
|
||||
await input.press('Enter')
|
||||
await input.fill('150')
|
||||
await input.press('Enter')
|
||||
await input.fill('50')
|
||||
await input.press('Enter')
|
||||
await expect(typebotViewer(page).locator('text=50')).toBeVisible()
|
||||
})
|
||||
})
|
48
apps/builder/playwright/tests/inputs/phone.spec.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import {
|
||||
createTypebots,
|
||||
parseDefaultBlockWithStep,
|
||||
} from '../../services/database'
|
||||
import { defaultPhoneInputOptions, InputStepType } from 'models'
|
||||
import { typebotViewer } from '../../services/selectorUtils'
|
||||
|
||||
const typebotId = 'phone-input-step'
|
||||
|
||||
test.describe('Phone input step', () => {
|
||||
test('options should work', async ({ page }) => {
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: InputStepType.PHONE,
|
||||
options: defaultPhoneInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
|
||||
await page.click('text=Preview')
|
||||
await expect(
|
||||
typebotViewer(page).locator(
|
||||
`input[placeholder="${defaultPhoneInputOptions.labels.placeholder}"]`
|
||||
)
|
||||
).toHaveAttribute('type', 'tel')
|
||||
await expect(typebotViewer(page).locator(`button`)).toBeDisabled()
|
||||
|
||||
await page.click(`text=${defaultPhoneInputOptions.labels.placeholder}`)
|
||||
await page.fill('#placeholder', '+33 XX XX XX XX')
|
||||
await page.fill('#button', 'Go')
|
||||
|
||||
await page.click('text=Restart')
|
||||
await typebotViewer(page)
|
||||
.locator(`input[placeholder="+33 XX XX XX XX"]`)
|
||||
.fill('+33 6 73 18 45 36')
|
||||
await expect(typebotViewer(page).locator(`img`)).toHaveAttribute(
|
||||
'alt',
|
||||
'France'
|
||||
)
|
||||
await typebotViewer(page).locator('text="Go"').click()
|
||||
await expect(typebotViewer(page).locator('text=+33673184536')).toBeVisible()
|
||||
})
|
||||
})
|
44
apps/builder/playwright/tests/inputs/text.spec.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import {
|
||||
createTypebots,
|
||||
parseDefaultBlockWithStep,
|
||||
} from '../../services/database'
|
||||
import { defaultTextInputOptions, InputStepType } from 'models'
|
||||
import { typebotViewer } from '../../services/selectorUtils'
|
||||
|
||||
const typebotId = 'text-input-step'
|
||||
|
||||
test.describe('Text input step', () => {
|
||||
test('options should work', async ({ page }) => {
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: InputStepType.TEXT,
|
||||
options: defaultTextInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
|
||||
await page.click('text=Preview')
|
||||
await expect(
|
||||
typebotViewer(page).locator(
|
||||
`input[placeholder="${defaultTextInputOptions.labels.placeholder}"]`
|
||||
)
|
||||
).toHaveAttribute('type', 'text')
|
||||
await expect(typebotViewer(page).locator(`button`)).toBeDisabled()
|
||||
|
||||
await page.click(`text=${defaultTextInputOptions.labels.placeholder}`)
|
||||
await page.fill('#placeholder', 'Your name...')
|
||||
await page.fill('#button', 'Go')
|
||||
await page.click('text=Long text?')
|
||||
|
||||
await page.click('text=Restart')
|
||||
await expect(
|
||||
typebotViewer(page).locator(`textarea[placeholder="Your name..."]`)
|
||||
).toBeVisible()
|
||||
await expect(typebotViewer(page).locator(`text=Go`)).toBeVisible()
|
||||
})
|
||||
})
|
43
apps/builder/playwright/tests/inputs/url.spec.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import {
|
||||
createTypebots,
|
||||
parseDefaultBlockWithStep,
|
||||
} from '../../services/database'
|
||||
import { defaultUrlInputOptions, InputStepType } from 'models'
|
||||
import { typebotViewer } from '../../services/selectorUtils'
|
||||
|
||||
const typebotId = 'url-input-step'
|
||||
|
||||
test.describe('Url input step', () => {
|
||||
test('options should work', async ({ page }) => {
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: InputStepType.URL,
|
||||
options: defaultUrlInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
|
||||
await page.click('text=Preview')
|
||||
await expect(
|
||||
typebotViewer(page).locator(
|
||||
`input[placeholder="${defaultUrlInputOptions.labels.placeholder}"]`
|
||||
)
|
||||
).toHaveAttribute('type', 'url')
|
||||
await expect(typebotViewer(page).locator(`button`)).toBeDisabled()
|
||||
|
||||
await page.click(`text=${defaultUrlInputOptions.labels.placeholder}`)
|
||||
await page.fill('#placeholder', 'Your URL...')
|
||||
await expect(page.locator('text=Your URL...')).toBeVisible()
|
||||
await page.fill('#button', 'Go')
|
||||
|
||||
await page.click('text=Restart')
|
||||
await expect(
|
||||
typebotViewer(page).locator(`input[placeholder="Your URL..."]`)
|
||||
).toBeVisible()
|
||||
})
|
||||
})
|
@ -0,0 +1,34 @@
|
||||
import test from '@playwright/test'
|
||||
import {
|
||||
createTypebots,
|
||||
parseDefaultBlockWithStep,
|
||||
} from '../../services/database'
|
||||
import { defaultGoogleAnalyticsOptions, IntegrationStepType } from 'models'
|
||||
|
||||
const typebotId = 'google-analytics-step'
|
||||
|
||||
test.describe('Google Analytics step', () => {
|
||||
test('its configuration should work', async ({ page }) => {
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({
|
||||
type: IntegrationStepType.GOOGLE_ANALYTICS,
|
||||
options: defaultGoogleAnalyticsOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
await page.click('text=Configure...')
|
||||
await page.fill('input[placeholder="G-123456..."]', 'G-VWX9WG1TNS')
|
||||
await page.fill('input[placeholder="Example: Typebot"]', 'Typebot')
|
||||
await page.fill(
|
||||
'input[placeholder="Example: Submit email"]',
|
||||
'Submit email'
|
||||
)
|
||||
await page.click('text=Advanced')
|
||||
await page.fill('input[placeholder="Example: Campaign Z"]', 'Campaign Z')
|
||||
await page.fill('input[placeholder="Example: 0"]', '0')
|
||||
})
|
||||
})
|
163
apps/builder/playwright/tests/integrations/googleSheets.spec.ts
Normal file
@ -0,0 +1,163 @@
|
||||
import test, { expect, Page } from '@playwright/test'
|
||||
import { importTypebotInDatabase } from '../../services/database'
|
||||
import path from 'path'
|
||||
import { typebotViewer } from '../../services/selectorUtils'
|
||||
|
||||
test.describe.parallel('Google sheets integration', () => {
|
||||
test('Insert row should work', async ({ page }) => {
|
||||
const typebotId = 'google-sheets-insert'
|
||||
await importTypebotInDatabase(
|
||||
path.join(
|
||||
__dirname,
|
||||
'../../fixtures/typebots/integrations/googleSheets.json'
|
||||
),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
await fillInSpreadsheetInfo(page)
|
||||
await page.click('text=Select an operation')
|
||||
await page.click('text=Insert a row')
|
||||
|
||||
await page.click('text=Select a column')
|
||||
await page.click('text="Email" >> nth = 1')
|
||||
await page.click('[aria-label="Insert a variable"]')
|
||||
await page.click('text="Email" >> nth = 2')
|
||||
|
||||
await page.click('text=Add a value')
|
||||
await page.click('text=Select a column')
|
||||
await page.click('text=First name')
|
||||
await page.fill(
|
||||
'input[placeholder="Type a value..."] >> nth = 1',
|
||||
'Georges'
|
||||
)
|
||||
|
||||
await page.click('text=Preview')
|
||||
await typebotViewer(page)
|
||||
.locator('input[placeholder="Type your email..."]')
|
||||
.fill('georges@gmail.com')
|
||||
await typebotViewer(page)
|
||||
.locator('input[placeholder="Type your email..."]')
|
||||
.press('Enter')
|
||||
await page.waitForResponse(
|
||||
(resp) =>
|
||||
resp
|
||||
.request()
|
||||
.url()
|
||||
.includes(
|
||||
'/api/integrations/google-sheets/spreadsheets/1k_pIDw3YHl9tlZusbBVSBRY0PeRPd2H6t4Nj7rwnOtM/sheets/0'
|
||||
) &&
|
||||
resp.status() === 200 &&
|
||||
resp.request().method() === 'POST'
|
||||
)
|
||||
})
|
||||
|
||||
test('Update row should work', async ({ page }) => {
|
||||
const typebotId = 'google-sheets-update'
|
||||
await importTypebotInDatabase(
|
||||
path.join(
|
||||
__dirname,
|
||||
'../../fixtures/typebots/integrations/googleSheets.json'
|
||||
),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
await fillInSpreadsheetInfo(page)
|
||||
await page.click('text=Select an operation')
|
||||
await page.click('text=Update a row')
|
||||
|
||||
await page.click('text=Select a column')
|
||||
await page.click('text="Email" >> nth = 1')
|
||||
await page.click('[aria-label="Insert a variable"]')
|
||||
await page.click('text="Email" >> nth = 2')
|
||||
|
||||
await page.click('text=Select a column')
|
||||
await page.click('text=Last name')
|
||||
await page.fill(
|
||||
'input[placeholder="Type a value..."] >> nth = 1',
|
||||
'Last name'
|
||||
)
|
||||
|
||||
await page.click('text=Preview')
|
||||
await typebotViewer(page)
|
||||
.locator('input[placeholder="Type your email..."]')
|
||||
.fill('test@test.com')
|
||||
await typebotViewer(page)
|
||||
.locator('input[placeholder="Type your email..."]')
|
||||
.press('Enter')
|
||||
await page.waitForResponse(
|
||||
(resp) =>
|
||||
resp
|
||||
.request()
|
||||
.url()
|
||||
.includes(
|
||||
'/api/integrations/google-sheets/spreadsheets/1k_pIDw3YHl9tlZusbBVSBRY0PeRPd2H6t4Nj7rwnOtM/sheets/0'
|
||||
) &&
|
||||
resp.status() === 200 &&
|
||||
resp.request().method() === 'PATCH'
|
||||
)
|
||||
})
|
||||
|
||||
test('Get row should work', async ({ page }) => {
|
||||
const typebotId = 'google-sheets-get'
|
||||
await importTypebotInDatabase(
|
||||
path.join(
|
||||
__dirname,
|
||||
'../../fixtures/typebots/integrations/googleSheetsGet.json'
|
||||
),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
await fillInSpreadsheetInfo(page)
|
||||
await page.click('text=Select an operation')
|
||||
await page.click('text=Get data from sheet')
|
||||
|
||||
await page.click('text=Select a column')
|
||||
await page.click('text="Email" >> nth = 1')
|
||||
await page.click('[aria-label="Insert a variable"]')
|
||||
await page.click('text="Email" >> nth = 2')
|
||||
|
||||
await page.click('text=Select a column')
|
||||
await page.click('text="First name"')
|
||||
await createNewVar(page, 'First name')
|
||||
|
||||
await page.click('text=Add a value')
|
||||
|
||||
await page.click('text=Select a column')
|
||||
await page.click('text="Last name"')
|
||||
await createNewVar(page, 'Last name')
|
||||
|
||||
await page.click('text=Preview')
|
||||
await typebotViewer(page)
|
||||
.locator('input[placeholder="Type your email..."]')
|
||||
.fill('test2@test.com')
|
||||
await typebotViewer(page)
|
||||
.locator('input[placeholder="Type your email..."]')
|
||||
.press('Enter')
|
||||
await expect(
|
||||
typebotViewer(page).locator('text=Your name is: John Smith')
|
||||
).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
const fillInSpreadsheetInfo = async (page: Page) => {
|
||||
await page.click('text=Configure...')
|
||||
await page.click('text=Select an account')
|
||||
await page.click('text=test2@gmail.com')
|
||||
|
||||
await page.fill('input[placeholder="Search for spreadsheet"]', 'CR')
|
||||
await page.click('text=CRM')
|
||||
|
||||
await page.fill('input[placeholder="Select the sheet"]', 'Sh')
|
||||
await page.click('text=Sheet1')
|
||||
}
|
||||
|
||||
const createNewVar = async (page: Page, name: string) => {
|
||||
await page.fill('input[placeholder="Select a variable"] >> nth=-1', name)
|
||||
await page.click(`text=Create "${name}"`)
|
||||
}
|
70
apps/builder/playwright/tests/integrations/webhook.spec.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import test, { expect, Page } from '@playwright/test'
|
||||
import { importTypebotInDatabase } from '../../services/database'
|
||||
import path from 'path'
|
||||
|
||||
const typebotId = 'webhook-step'
|
||||
|
||||
test.describe('Webhook step', () => {
|
||||
test('its configuration should work', async ({ page }) => {
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../../fixtures/typebots/integrations/webhook.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
await page.click('text=Configure...')
|
||||
await page.click('text=GET')
|
||||
await page.click('text=POST')
|
||||
await page.fill(
|
||||
'input[placeholder="Your Webhook URL..."]',
|
||||
`${process.env.NEXTAUTH_URL}/api/mock/webhook`
|
||||
)
|
||||
|
||||
await page.click('text=Query params')
|
||||
await page.fill('input[placeholder="e.g. email"]', 'firstParam')
|
||||
await page.fill('input[placeholder="e.g. {{Email}}"]', '{{secret 1}}')
|
||||
|
||||
await page.click('text=Add a param')
|
||||
await page.fill('input[placeholder="e.g. email"] >> nth=1', 'secondParam')
|
||||
await page.fill(
|
||||
'input[placeholder="e.g. {{Email}}"] >> nth=1',
|
||||
'{{secret 2}}'
|
||||
)
|
||||
|
||||
await page.click('text=Headers')
|
||||
await page.fill('input[placeholder="e.g. Content-Type"]', 'Custom-Typebot')
|
||||
await page.fill(
|
||||
'input[placeholder="e.g. application/json"]',
|
||||
'{{secret 3}}'
|
||||
)
|
||||
|
||||
await page.click('text=Body')
|
||||
await page.fill('div[role="textbox"]', '{ "customField": "{{secret 4}}" }')
|
||||
|
||||
await page.click('text=Variable values for test')
|
||||
await addTestVariable(page, 'secret 1', 'secret1')
|
||||
await page.click('text=Add an entry')
|
||||
await addTestVariable(page, 'secret 2', 'secret2')
|
||||
await page.click('text=Add an entry')
|
||||
await addTestVariable(page, 'secret 3', 'secret3')
|
||||
await page.click('text=Add an entry')
|
||||
await addTestVariable(page, 'secret 4', 'secret4')
|
||||
|
||||
await page.click('text=Test the request')
|
||||
await expect(page.locator('div[role="textbox"] >> nth=-1')).toContainText(
|
||||
'"statusCode": 200'
|
||||
)
|
||||
|
||||
await page.click('text=Save in variables')
|
||||
await page.click('input[placeholder="Select the data"]')
|
||||
await page.click('text=data[0].name')
|
||||
})
|
||||
})
|
||||
|
||||
const addTestVariable = async (page: Page, name: string, value: string) => {
|
||||
await page.click('[data-testid="variables-input"] >> nth=-1')
|
||||
await page.click(`text="${name}"`)
|
||||
await page.fill('input >> nth=-1', value)
|
||||
}
|
73
apps/builder/playwright/tests/logic/condition.spec.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import test, { expect, Page } from '@playwright/test'
|
||||
import path from 'path'
|
||||
import { typebotViewer } from '../../services/selectorUtils'
|
||||
import { importTypebotInDatabase } from '../../services/database'
|
||||
|
||||
const typebotId = 'condition-step'
|
||||
|
||||
test.describe('Condition step', () => {
|
||||
test('its configuration should work', async ({ page }) => {
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../../fixtures/typebots/logic/condition.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
await page.click('text=Configure...')
|
||||
await page.fill('input[placeholder="Search for a variable"]', 'Age')
|
||||
await page.click('button:has-text("Age")')
|
||||
await page.click('button:has-text("Select an operator")')
|
||||
await page.click('button:has-text("Greater than")', { force: true })
|
||||
await page.fill('input[placeholder="Type a value..."]', '80')
|
||||
|
||||
await page.click('button:has-text("Add a comparison")')
|
||||
|
||||
await page.fill(
|
||||
':nth-match(input[placeholder="Search for a variable"], 2)',
|
||||
'Age'
|
||||
)
|
||||
await page.click('button:has-text("Age")')
|
||||
await page.click('button:has-text("Select an operator")')
|
||||
await page.click('button:has-text("Less than")', { force: true })
|
||||
await page.fill(
|
||||
':nth-match(input[placeholder="Type a value..."], 2)',
|
||||
'100'
|
||||
)
|
||||
|
||||
await page.click('text=Configure...')
|
||||
await page.fill('input[placeholder="Search for a variable"]', 'Age')
|
||||
await page.click('button:has-text("Age")')
|
||||
await page.click('button:has-text("Select an operator")')
|
||||
await page.click('button:has-text("Greater than")', { force: true })
|
||||
await page.fill('input[placeholder="Type a value..."]', '20')
|
||||
|
||||
await page.click('text=Preview')
|
||||
await typebotViewer(page)
|
||||
.locator('input[placeholder="Type your answer..."]')
|
||||
.fill('15')
|
||||
await typebotViewer(page).locator('text=Send').click()
|
||||
await expect(
|
||||
typebotViewer(page).locator('text=You are younger than 20')
|
||||
).toBeVisible()
|
||||
|
||||
await page.click('text=Restart')
|
||||
await typebotViewer(page)
|
||||
.locator('input[placeholder="Type your answer..."]')
|
||||
.fill('45')
|
||||
await typebotViewer(page).locator('text=Send').click()
|
||||
await expect(
|
||||
typebotViewer(page).locator('text=You are older than 20')
|
||||
).toBeVisible()
|
||||
|
||||
await page.click('text=Restart')
|
||||
await typebotViewer(page)
|
||||
.locator('input[placeholder="Type your answer..."]')
|
||||
.fill('90')
|
||||
await typebotViewer(page).locator('text=Send').click()
|
||||
await expect(
|
||||
typebotViewer(page).locator('text=You are older than 80')
|
||||
).toBeVisible()
|
||||
})
|
||||
})
|
37
apps/builder/playwright/tests/logic/redirect.spec.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import path from 'path'
|
||||
import { typebotViewer } from '../../services/selectorUtils'
|
||||
import { importTypebotInDatabase } from '../../services/database'
|
||||
|
||||
const typebotId = 'redirect-step'
|
||||
|
||||
test.describe('Redirect step', () => {
|
||||
test('its configuration should work', async ({ page, context }) => {
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../../fixtures/typebots/logic/redirect.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
await page.click('text=Configure...')
|
||||
await page.fill('input[placeholder="Type a URL..."]', 'google.com')
|
||||
|
||||
await page.click('text=Preview')
|
||||
await typebotViewer(page).locator('text=Go to URL').click()
|
||||
await expect(page).toHaveURL('https://www.google.com')
|
||||
await page.goBack()
|
||||
|
||||
await page.click('text=Redirect to google.com')
|
||||
await page.click('text=Open in new tab')
|
||||
|
||||
await page.click('text=Preview')
|
||||
const [newPage] = await Promise.all([
|
||||
context.waitForEvent('page'),
|
||||
typebotViewer(page).locator('text=Go to URL').click(),
|
||||
])
|
||||
await newPage.waitForLoadState()
|
||||
await expect(newPage).toHaveURL('https://www.google.com')
|
||||
})
|
||||
})
|
44
apps/builder/playwright/tests/logic/setVariable.spec.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import path from 'path'
|
||||
import { typebotViewer } from '../../services/selectorUtils'
|
||||
import { importTypebotInDatabase } from '../../services/database'
|
||||
|
||||
const typebotId = 'set-variable-step'
|
||||
|
||||
test.describe('Set variable step', () => {
|
||||
test('its configuration should work', async ({ page, context }) => {
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../../fixtures/typebots/logic/setVariable.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
|
||||
await page.goto(`/typebots/${typebotId}/edit`)
|
||||
await page.click('text=Type a number...')
|
||||
await page.fill('input[placeholder="Select a variable"]', 'Num')
|
||||
await page.click('text=Create "Num"')
|
||||
|
||||
await page.click('text=Click to edit... >> nth = 0')
|
||||
await page.fill('input[placeholder="Select a variable"]', 'Total')
|
||||
await page.click('text=Create "Total"')
|
||||
await page.fill('textarea', '1000 * {{Num}}')
|
||||
|
||||
await page.click('text=Click to edit...')
|
||||
await page.fill('input[placeholder="Select a variable"]', 'Custom var')
|
||||
await page.click('text=Create "Custom var"')
|
||||
await page.fill('textarea', 'Custom value')
|
||||
|
||||
await page.click('text=Preview')
|
||||
await typebotViewer(page)
|
||||
.locator('input[placeholder="Type a number..."]')
|
||||
.fill('365')
|
||||
await typebotViewer(page).locator('text=Send').click()
|
||||
await expect(
|
||||
typebotViewer(page).locator('text=Total: 365000')
|
||||
).toBeVisible()
|
||||
await expect(
|
||||
typebotViewer(page).locator('text=Custom var: Custom value')
|
||||
).toBeVisible()
|
||||
})
|
||||
})
|
102
apps/builder/playwright/tests/results.spec.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import test, { expect, Page } from '@playwright/test'
|
||||
import { readFileSync } from 'fs'
|
||||
import { InputStepType } from 'models'
|
||||
import { parse } from 'papaparse'
|
||||
import {
|
||||
createResults,
|
||||
createTypebots,
|
||||
parseDefaultBlockWithStep,
|
||||
} from '../services/database'
|
||||
import { deleteButtonInConfirmDialog } from '../services/selectorUtils'
|
||||
|
||||
const typebotId = 'typebot-for-results'
|
||||
|
||||
test.describe('Results page', () => {
|
||||
test('results should be deletable', async ({ page }) => {
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultBlockWithStep({ type: InputStepType.TEXT }),
|
||||
},
|
||||
])
|
||||
await createResults({ typebotId })
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
await selectFirstResults(page)
|
||||
await page.click('button:has-text("Delete2")')
|
||||
await deleteButtonInConfirmDialog(page).click()
|
||||
await expect(page.locator('text=content199')).toBeHidden()
|
||||
await expect(page.locator('text=content198')).toBeHidden()
|
||||
await page.check(':nth-match(input[type="checkbox"], 1)', { force: true })
|
||||
await page.click('button:has-text("Delete198")')
|
||||
await deleteButtonInConfirmDialog(page).click()
|
||||
await expect(page.locator(':nth-match(tr, 2)')).toBeHidden()
|
||||
})
|
||||
|
||||
test('submissions table should have infinite scroll', async ({ page }) => {
|
||||
const scrollToBottom = () =>
|
||||
page.evaluate(() => {
|
||||
const tableWrapper = document.querySelector('.table-wrapper')
|
||||
if (!tableWrapper) return
|
||||
tableWrapper.scrollTo(0, tableWrapper.scrollHeight)
|
||||
})
|
||||
|
||||
await createResults({ typebotId })
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
await expect(page.locator('text=content199')).toBeVisible()
|
||||
|
||||
await expect(page.locator('text=content149')).toBeHidden()
|
||||
await scrollToBottom()
|
||||
await expect(page.locator('text=content149')).toBeVisible()
|
||||
|
||||
await expect(page.locator('text=content99')).toBeHidden()
|
||||
await scrollToBottom()
|
||||
await expect(page.locator('text=content99')).toBeVisible()
|
||||
|
||||
await expect(page.locator('text=content49')).toBeHidden()
|
||||
await scrollToBottom()
|
||||
await expect(page.locator('text=content49')).toBeVisible()
|
||||
await expect(page.locator('text=content0')).toBeVisible()
|
||||
})
|
||||
|
||||
test('should correctly export selection in CSV', async ({ page }) => {
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
await selectFirstResults(page)
|
||||
const [download] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.locator('button:has-text("Export2")').click(),
|
||||
])
|
||||
const path = await download.path()
|
||||
expect(path).toBeDefined()
|
||||
const file = readFileSync(path as string).toString()
|
||||
const { data } = parse(file)
|
||||
validateExportSelection(data)
|
||||
|
||||
await page.check(':nth-match(input[type="checkbox"], 1)', { force: true })
|
||||
const [downloadAll] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.locator('button:has-text("Export200")').click(),
|
||||
])
|
||||
const pathAll = await downloadAll.path()
|
||||
expect(pathAll).toBeDefined()
|
||||
const fileAll = readFileSync(pathAll as string).toString()
|
||||
const { data: dataAll } = parse(fileAll)
|
||||
validateExportAll(dataAll)
|
||||
})
|
||||
})
|
||||
|
||||
const validateExportSelection = (data: unknown[]) => {
|
||||
expect(data).toHaveLength(3)
|
||||
expect((data[1] as unknown[])[1]).toBe('content199')
|
||||
expect((data[2] as unknown[])[1]).toBe('content198')
|
||||
}
|
||||
|
||||
const validateExportAll = (data: unknown[]) => {
|
||||
expect(data).toHaveLength(201)
|
||||
expect((data[1] as unknown[])[1]).toBe('content199')
|
||||
expect((data[200] as unknown[])[1]).toBe('content0')
|
||||
}
|
||||
|
||||
const selectFirstResults = async (page: Page) => {
|
||||
await page.check(':nth-match(input[type="checkbox"], 2)', { force: true })
|
||||
return page.check(':nth-match(input[type="checkbox"], 3)', { force: true })
|
||||
}
|
91
apps/builder/playwright/tests/settings.spec.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import path from 'path'
|
||||
import { importTypebotInDatabase } from '../services/database'
|
||||
import { typebotViewer } from '../services/selectorUtils'
|
||||
|
||||
test.describe.parallel('Settings page', () => {
|
||||
test.describe('General', () => {
|
||||
test('should reflect change in real-time', async ({ page }) => {
|
||||
const typebotId = 'general-settings-typebot'
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../fixtures/typebots/theme.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
await page.goto(`/typebots/${typebotId}/settings`)
|
||||
await expect(
|
||||
typebotViewer(page).locator('a:has-text("Made with Typebot")')
|
||||
).toHaveAttribute('href', 'https://www.typebot.io/?utm_source=litebadge')
|
||||
await page.click('button:has-text("General")')
|
||||
await page.uncheck('input[type="checkbox"]', { force: true })
|
||||
await expect(
|
||||
typebotViewer(page).locator('a:has-text("Made with Typebot")')
|
||||
).toBeHidden()
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Typing emulation', () => {
|
||||
test('should be fillable', async ({ page }) => {
|
||||
const typebotId = 'typing-emulation-typebot'
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../fixtures/typebots/theme.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
await page.goto(`/typebots/${typebotId}/settings`)
|
||||
await page.click('button:has-text("Typing emulation")')
|
||||
await page.fill('[data-testid="speed"] input', '350')
|
||||
await page.fill('[data-testid="max-delay"] input', '1.5')
|
||||
await page.uncheck(':nth-match(input[type="checkbox"], 2)', {
|
||||
force: true,
|
||||
})
|
||||
await expect(page.locator('[data-testid="speed"]')).toBeHidden()
|
||||
await expect(page.locator('[data-testid="max-delay"]')).toBeHidden()
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Metadata', () => {
|
||||
test('should be fillable', async ({ page }) => {
|
||||
const favIconUrl = 'https://www.baptistearno.com/favicon.png'
|
||||
const imageUrl = 'https://www.baptistearno.com/images/site-preview.png'
|
||||
const typebotId = 'metadata-typebot'
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../fixtures/typebots/theme.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
await page.goto(`/typebots/${typebotId}/settings`)
|
||||
await page.click('button:has-text("Metadata")')
|
||||
|
||||
// Fav icon
|
||||
const favIconImg = page.locator(':nth-match(img, 1)')
|
||||
await expect(favIconImg).toHaveAttribute('src', '/favicon.png')
|
||||
await favIconImg.click()
|
||||
await expect(page.locator('text=Giphy')).toBeHidden()
|
||||
await page.click('button:has-text("Embed link")')
|
||||
await page.fill(
|
||||
'input[placeholder="Paste the image link..."]',
|
||||
favIconUrl
|
||||
)
|
||||
await expect(favIconImg).toHaveAttribute('src', favIconUrl)
|
||||
|
||||
// Website image
|
||||
const websiteImg = page.locator(':nth-match(img, 2)')
|
||||
await expect(websiteImg).toHaveAttribute('src', '/viewer-preview.png')
|
||||
await websiteImg.click()
|
||||
await expect(page.locator('text=Giphy')).toBeHidden()
|
||||
await page.click('button:has-text("Embed link")')
|
||||
await page.fill('input[placeholder="Paste the image link..."]', imageUrl)
|
||||
await expect(websiteImg).toHaveAttribute('src', imageUrl)
|
||||
|
||||
// Title
|
||||
await page.fill('input#title', 'Awesome typebot')
|
||||
|
||||
// Description
|
||||
await page.fill('textarea#description', 'Lorem ipsum')
|
||||
})
|
||||
})
|
||||
})
|
123
apps/builder/playwright/tests/theme.spec.ts
Normal file
@ -0,0 +1,123 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import path from 'path'
|
||||
import { importTypebotInDatabase } from '../services/database'
|
||||
import { typebotViewer } from '../services/selectorUtils'
|
||||
|
||||
test.describe.parallel('Theme page', () => {
|
||||
test.describe('General', () => {
|
||||
test('should reflect change in real-time', async ({ page }) => {
|
||||
const typebotId = 'general-theme-typebot'
|
||||
const chatContainer = typebotViewer(page).locator(
|
||||
'[data-testid="container"]'
|
||||
)
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../fixtures/typebots/theme.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
await page.goto(`/typebots/${typebotId}/theme`)
|
||||
await page.click('button:has-text("General")')
|
||||
|
||||
// Font
|
||||
await page.fill('input[type="text"]', 'Roboto Slab')
|
||||
await expect(chatContainer).toHaveCSS('font-family', '"Roboto Slab"')
|
||||
|
||||
// BG color
|
||||
await expect(chatContainer).toHaveCSS(
|
||||
'background-color',
|
||||
'rgba(0, 0, 0, 0)'
|
||||
)
|
||||
await page.click('text=Color')
|
||||
await page.click('[aria-label="Pick a color"]')
|
||||
await page.fill('[aria-label="Color value"]', '#2a9d8f')
|
||||
await expect(chatContainer).toHaveCSS(
|
||||
'background-color',
|
||||
'rgb(42, 157, 143)'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Chat', () => {
|
||||
test('should reflect change in real-time', async ({ page }) => {
|
||||
const typebotId = 'chat-theme-typebot'
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../fixtures/typebots/theme.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
await page.goto(`/typebots/${typebotId}/theme`)
|
||||
await page.click('button:has-text("Chat")')
|
||||
|
||||
// Host bubbles
|
||||
await page.click(':nth-match([aria-label="Pick a color"], 1)')
|
||||
await page.fill('[aria-label="Color value"]', '#2a9d8f')
|
||||
await page.click(':nth-match([aria-label="Pick a color"], 2)')
|
||||
await page.fill('[aria-label="Color value"]', '#ffffff')
|
||||
const hostBubble = typebotViewer(page).locator(
|
||||
'[data-testid="host-bubble"]'
|
||||
)
|
||||
await expect(hostBubble).toHaveCSS(
|
||||
'background-color',
|
||||
'rgb(42, 157, 143)'
|
||||
)
|
||||
await expect(hostBubble).toHaveCSS('color', 'rgb(255, 255, 255)')
|
||||
|
||||
// Buttons
|
||||
await page.click(':nth-match([aria-label="Pick a color"], 5)')
|
||||
await page.fill('[aria-label="Color value"]', '#7209b7')
|
||||
await page.click(':nth-match([aria-label="Pick a color"], 6)')
|
||||
await page.fill('[aria-label="Color value"]', '#e9c46a')
|
||||
const button = typebotViewer(page).locator('[data-testid="button"]')
|
||||
await expect(button).toHaveCSS('background-color', 'rgb(114, 9, 183)')
|
||||
await expect(button).toHaveCSS('color', 'rgb(233, 196, 106)')
|
||||
|
||||
// Guest bubbles
|
||||
await page.click(':nth-match([aria-label="Pick a color"], 3)')
|
||||
await page.fill('[aria-label="Color value"]', '#d8f3dc')
|
||||
await page.click(':nth-match([aria-label="Pick a color"], 4)')
|
||||
await page.fill('[aria-label="Color value"]', '#264653')
|
||||
await typebotViewer(page).locator('text=Go').click()
|
||||
const guestBubble = typebotViewer(page).locator(
|
||||
'[data-testid="guest-bubble"]'
|
||||
)
|
||||
await expect(guestBubble).toHaveCSS(
|
||||
'background-color',
|
||||
'rgb(216, 243, 220)'
|
||||
)
|
||||
await expect(guestBubble).toHaveCSS('color', 'rgb(38, 70, 83)')
|
||||
|
||||
// Input
|
||||
await page.click(':nth-match([aria-label="Pick a color"], 7)')
|
||||
await page.fill('[aria-label="Color value"]', '#ffe8d6')
|
||||
await page.click(':nth-match([aria-label="Pick a color"], 8)')
|
||||
await page.fill('[aria-label="Color value"]', '#023e8a')
|
||||
await typebotViewer(page).locator('text=Go').click()
|
||||
const input = typebotViewer(page).locator('.typebot-input')
|
||||
await expect(input).toHaveCSS('background-color', 'rgb(255, 232, 214)')
|
||||
await expect(input).toHaveCSS('color', 'rgb(2, 62, 138)')
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Custom CSS', () => {
|
||||
test('should reflect change in real-time', async ({ page }) => {
|
||||
const typebotId = 'custom-css-theme-typebot'
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../fixtures/typebots/theme.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
await page.goto(`/typebots/${typebotId}/theme`)
|
||||
await page.click('button:has-text("Custom CSS")')
|
||||
await page.fill(
|
||||
'div[role="textbox"]',
|
||||
'.typebot-button {background-color: green}'
|
||||
)
|
||||
await expect(
|
||||
typebotViewer(page).locator('[data-testid="button"]')
|
||||
).toHaveCSS('background-color', 'rgb(0, 128, 0)')
|
||||
})
|
||||
})
|
||||
})
|