@@ -13,7 +13,7 @@ console.log(`renderVisualizations.js: dirname=${__dirname}`);
13
13
14
14
/**
15
15
* Crops the image in the buffer so that there is no empty frame around it.
16
- * @param {Buffer } buffer
16
+ * @param {Buffer } buffer
17
17
* @returns Buffer
18
18
*/
19
19
const autoCropImageBuffer = async ( buffer ) => {
@@ -31,41 +31,72 @@ const autoCropImageBuffer = async (buffer) => {
31
31
*/
32
32
const camelToKebabCase = ( str ) => str . replace ( / [ A - Z ] / g, ( letter ) => `-${ letter . toLowerCase ( ) } ` ) ;
33
33
34
+ /**
35
+ * Take a screenshot after an error happened.
36
+ *
37
+ * @param {string } htmlFilename
38
+ * @param {string } reason
39
+ */
40
+ const makeScreenshotOfError = async ( page , htmlFilename , reason ) => {
41
+ const reportName = basename ( htmlFilename , ".html" ) ;
42
+ const directoryName = camelToKebabCase ( reportName ) ;
43
+ console . log ( `Taking an error screenshot of report ${ reportName } . Reason: ${ reason } ` ) ;
44
+ await page . screenshot ( { path : `./${ directoryName } /error-${ reportName } -${ reason } .png` , omitBackground : false } ) ;
45
+ } ;
46
+
47
+ /**
48
+ * Handle a catched error by taking a screenshot.
49
+ *
50
+ * @param {string } htmlFilename
51
+ * @param {string } reason
52
+ * @return
53
+ */
54
+ const handleErrorWithScreenshot = ( page , htmlFilename , reason ) => async ( error ) => {
55
+ await makeScreenshotOfError ( page , htmlFilename , reason ) ;
56
+ throw new Error ( error ) ;
57
+ } ;
34
58
/**
35
59
* Creates a new page and takes a screenshot of all canvas tags that are contained within a div.
36
60
* Note: Don't run this in parallel. See https://github.com/puppeteer/puppeteer/issues/1479
37
61
* @param {Browser } browser
38
62
* @param {string } htmlFilename
39
63
*/
40
64
const takeCanvasScreenshots = async ( browser , htmlFilename ) => {
65
+ const reportName = basename ( htmlFilename , ".html" ) ;
66
+ const directoryName = camelToKebabCase ( reportName ) ;
67
+ if ( ! existsSync ( directoryName ) ) {
68
+ mkdirSync ( directoryName ) ;
69
+ }
70
+
41
71
const page = await browser . newPage ( ) ;
72
+ page . on ( "requestfailed" , ( request ) => console . log ( `${ request . failure ( ) . errorText } ${ request . url ( ) } ` ) ) ;
42
73
await page . setViewport ( { width : 1500 , height : 1000 , isMobile : false , isLandscape : true , hasTouch : false , deviceScaleFactor : 1 } ) ;
43
74
44
75
console . log ( `Loading ${ htmlFilename } ` ) ;
45
76
await page . goto ( `file://${ htmlFilename } ` ) ;
46
77
78
+ if ( ! process . env . NEO4J_INITIAL_PASSWORD ) {
79
+ throw new Error ( "Missing environment variable NEO4J_INITIAL_PASSWORD" ) ;
80
+ }
47
81
// Login with Neo4j server password from the environment variable NEO4J_INITIAL_PASSWORD
48
82
const loginButton = await page . waitForSelector ( "#neo4j-server-login" ) ;
49
83
await page . type ( "#neo4j-server-password" , process . env . NEO4J_INITIAL_PASSWORD ) ;
50
84
await loginButton . click ( ) ;
51
85
52
86
// Wait for the graph visualization to be rendered onto a HTML5 canvas
53
87
console . log ( `Waiting for visualizations to be finished` ) ;
54
- await page . waitForSelector ( ".visualization-finished" , { timeout : 90_000 } ) ;
88
+ await page
89
+ . waitForSelector ( ".visualization-finished" , { timeout : 90_000 } )
90
+ . catch ( handleErrorWithScreenshot ( page , htmlFilename , "visualization-did-not-finish" ) ) ;
55
91
56
92
// Get all HTML canvas tag elements
57
93
const canvasElements = await page . $$ ( "canvas" ) ;
58
94
if ( canvasElements . length <= 0 ) {
59
- console . error ( `No elements with CSS selector ' canvas' found in ${ htmlFilename } ` ) ;
95
+ await makeScreenshotOfError ( page , htmlFilename , "no- canvas- found" ) ;
60
96
}
61
97
console . log ( `Found ${ canvasElements . length } visualizations` ) ;
62
98
63
99
// Take a png screenshot of every canvas element and save them with increasing indices
64
- const reportName = basename ( htmlFilename , ".html" ) ;
65
- const directoryName = camelToKebabCase ( reportName ) ;
66
- if ( ! existsSync ( directoryName ) ) {
67
- mkdirSync ( directoryName ) ;
68
- }
69
100
await Promise . all (
70
101
Array . from ( canvasElements ) . map ( async ( canvasElement , index ) => {
71
102
console . log ( `Exporting image ${ reportName } -${ index } .png...` ) ;
@@ -74,10 +105,8 @@ const takeCanvasScreenshots = async (browser, htmlFilename) => {
74
105
} , canvasElement ) ;
75
106
let data = Buffer . from ( dataUrl . split ( "," ) . pop ( ) , "base64" ) ;
76
107
console . log ( `Cropping image ${ reportName } -${ index } .png...` ) ;
77
- data = await autoCropImageBuffer ( data ) ;
108
+ data = await autoCropImageBuffer ( data ) . catch ( handleErrorWithScreenshot ( page , htmlFilename , `failed-to-crop-image- ${ index } ` ) ) ;
78
109
writeFileSync ( `./${ directoryName } /${ reportName } -${ index } .png` , data ) ;
79
- // console.log(`Taking screenshot ${reportName} of canvas ${index} in ${htmlFilename} of element...`);
80
- // await canvasElement.screenshot({ path: `./${directoryName}/${reportName}-${index}.png`, omitBackground: true });
81
110
} )
82
111
) ;
83
112
} ;
@@ -89,17 +118,34 @@ let browser;
89
118
* and takes a screenshot of the canvas elements using {@link takeCanvasScreenshots}.
90
119
*/
91
120
( async ( ) => {
92
- console . log ( 'renderVisualizations.js: Starting headless browser...' ) ;
93
- browser = await puppeteer . launch ( { headless : "new" } ) ; // { headless: false } for testing
121
+ console . log ( "renderVisualizations.js: Starting headless browser..." ) ;
122
+ browser = await puppeteer . launch ( {
123
+ headless : "new" ,
124
+ dumpio : true ,
125
+ args : [
126
+ "--enable-logging" ,
127
+ "--disable-search-engine-choice-screen" ,
128
+ "--ash-no-nudges" ,
129
+ "--no-first-run" ,
130
+ "--no-default-browser-check" ,
131
+ "--hide-scrollbars" ,
132
+ "--disable-features=Translate" ,
133
+ "--disable-features=InterestFeedContentSuggestions" ,
134
+ "--disable-extensions" ,
135
+ "--disable-default-apps" ,
136
+ "--disable-component-extensions-with-background-pages" ,
137
+ "--disable-client-side-phishing-detection" ,
138
+ "--use-gl=disabled" ,
139
+ "--disable-features=Vulkan" ,
140
+ ] ,
141
+ } ) ; // { headless: false } for testing
94
142
95
143
// Get all *.html files in this (script) directory and its subdirectories
96
- // The separate filter is needed to ignore the "node_modules" directory.
144
+ // The separate filter is needed to ignore the "node_modules" directory.
97
145
// Glob's build-in filter doesn't seem to work on Windows.
98
- const htmlFiles = globSync ( `${ __dirname } /**/*.html` , { absolute : true } ) . filter ( file => ! file . includes ( ' node_modules' ) ) ;
146
+ const htmlFiles = globSync ( `${ __dirname } /**/*.html` , { absolute : true } ) . filter ( ( file ) => ! file . includes ( " node_modules" ) ) ;
99
147
for ( const htmlFile of htmlFiles ) {
100
148
await takeCanvasScreenshots ( browser , htmlFile ) ;
101
149
}
102
150
console . log ( `renderVisualizations.js: Successfully rendered ${ htmlFiles . length } html file(s)` ) ;
103
- } ) ( )
104
- . catch ( ( err ) => console . error ( err ) )
105
- . finally ( ( ) => browser ?. close ( ) ) ;
151
+ } ) ( ) . finally ( ( ) => browser ?. close ( ) ) ;
0 commit comments