/
HtmlDataSource.ts
119 lines (100 loc) · 3.45 KB
/
HtmlDataSource.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
* Forms the HTML pages rendered to the client for Component / E2E testing,
* including the pre-hydration we use to bootstrap the script data for fast
* initial loading
*/
import type { DataContext } from '../DataContext'
import { getPathToDist, resolveFromPackages } from '@packages/resolve-dist'
import _ from 'lodash'
const PATH_TO_NON_PROXIED_ERROR = resolveFromPackages('server', 'lib', 'html', 'non_proxied_error.html')
export class HtmlDataSource {
constructor (private ctx: DataContext) {}
async fetchAppHtml () {
if (process.env.CYPRESS_INTERNAL_VITE_DEV) {
const response = await this.ctx.util.fetch(`http://localhost:${process.env.CYPRESS_INTERNAL_VITE_APP_PORT}/`, { method: 'GET' })
const html = await response.text()
return html
}
// Check if the file exists. If it doesn't, it probably means that Vite is re-building
// and we should retry a few times until the file exists
let retryCount = 0
let err
while (retryCount < 5) {
try {
let html = await this.ctx.fs.readFile(getPathToDist('app', 'index.html'), 'utf8')
return html.replace(
'<title>Cypress</title>',
`<title>${this.ctx.project.projectTitle(this.ctx.currentProject || '')}</title>`,
)
} catch (e) {
err = e
await new Promise((resolve) => setTimeout(resolve, 1000))
}
}
throw err
}
getPropertiesFromLegacyConfig (cfg: any) {
const keys = [
'baseUrl',
'browserUrl',
'port',
'proxyServer',
'proxyUrl',
'remote',
'testingType',
'componentTesting',
'reporterUrl',
'xhrUrl',
'namespace',
'socketIoRoute',
]
return _.pick(cfg, keys)
}
async makeServeConfig () {
const propertiesFromLegacyConfig = this.getPropertiesFromLegacyConfig(this.ctx._apis.projectApi.getConfig() ?? {})
let cfg = { ...propertiesFromLegacyConfig }
try {
cfg = {
...(await this.ctx.project.getConfig()),
...cfg,
}
} catch {
// Error getting config, we will show an error screen when we render the page
}
cfg.browser = this.ctx._apis.projectApi.getCurrentBrowser()
return {
projectName: this.ctx.lifecycleManager.projectTitle,
namespace: cfg.namespace || '__cypress-string',
base64Config: Buffer.from(JSON.stringify(cfg)).toString('base64'),
}
}
/**
* The app html includes the SSR'ed data to bootstrap the page for the app
*/
async appHtml (nonProxied: boolean) {
if (nonProxied) {
return this.ctx.fs.readFile(PATH_TO_NON_PROXIED_ERROR, 'utf-8')
}
const [appHtml, serveConfig] = await Promise.all([
this.fetchAppHtml(),
this.makeServeConfig(),
])
return this.replaceBody(appHtml, serveConfig)
}
private replaceBody (html: string, serveConfig: object) {
return html.replace('<body>', `
<body>
<script>
window.__RUN_MODE_SPECS__ = ${JSON.stringify(this.ctx.project.specs)}
window.__CYPRESS_MODE__ = ${JSON.stringify(this.ctx.isRunMode ? 'run' : 'open')};
window.__CYPRESS_CONFIG__ = ${JSON.stringify(serveConfig)};
window.__CYPRESS_TESTING_TYPE__ = '${this.ctx.coreData.currentTestingType}'
window.__CYPRESS_BROWSER__ = ${JSON.stringify(this.ctx.coreData.activeBrowser)}
${process.env.CYPRESS_INTERNAL_GQL_NO_SOCKET
? `window.__CYPRESS_GQL_NO_SOCKET__ = 'true';`
: ''
}
</script>
`)
}
}