Responsieve screenshots met Casper

Het maken van screenshots is vervelend, maar meestal moet het worden gedaan en meestal ben jij het - de ontwikkelaar - die het moet doen. Het maken van een paar screenshots is niet zo erg, maar laten we bijvoorbeeld zeggen dat je nu werkt aan een website met Responsive Web Design en je vijf keer zoveel screenshots moet nemen bij verschillende viewports. Die ene, twee seconden vervelende taak is nu begonnen aan het eten van je lunchtijd.


Intro

Vandaag ga ik een snel en eenvoudig script schrijven om enkele schermafbeeldingen van elke site op verschillende viewports te maken en de afbeeldingen op schijf op te slaan. Dit zag ik voor het eerst bij mediaqueri.es en begon het in mijn bouwproces te implementeren. Het is niet ideaal voor echte tests, omdat het meer als een sanitytest fungeert en een goed overzicht biedt voor alles waarmee ik misschien bezig ben, waarbij Responsive Web betrokken is.

Wanneer een build wordt uitgevoerd, kan een klein script met PhantomJS en CasperJS een screenshot krijgen bij verschillende viewports die ik heb gedefinieerd en een snel overzicht geven van elke gewenste pagina. Het is vooral goed wanneer je in een groter team werkt en je hebt misschien niet de tijd voor elke build om te gaan en controleert elke afzonderlijke pagina en module op verschillende resoluties. Het geeft je ook iets om de klant mogelijk met regelmatige tussenpozen te tonen, om weer te geven hoe zijn site op verschillende viewports buigt.

Opmerking: PhantomJS is een WebKit-browser zonder headers en alles wat wordt weergegeven zou gebruikmaken van WebKit-rendering, dus het is geen werkelijke weergave van hoe de site zou worden weergegeven op verschillende apparaten die verschillende browsers kunnen gebruiken en terwijl u de User Agent-tekenreeks die naar de site is geladen, dit heeft geen invloed op de rendering-engine.

PhantomJS heeft een geweldige JavaScript-API gebouwd met testen in gedachten. Voor een geweldige introductie tot PhantomJS en gebruik voor testen is er een handleiding hier op nettuts en controleer de officiële site en documentatie.

CasperJS is een toolkit die bovenop PhantomJS zit en het schrijven van Phantom-scripts vereenvoudigt door functies, methoden en syntactische suiker aan te bieden.


Installatie

Mogelijk hebt u Phantom al geïnstalleerd, vooral als u uw client-side code al test, zo niet, dan is het vrij eenvoudig en kunt u meer gedetailleerde instructies krijgen op de officiële site.

Voor Windows-gebruikers is er een uitvoerbaar bestand om te downloaden en uit te voeren.

Voor Mac-gebruikers is er zowel het binaire bestand als je kunt installeren met behulp van Homebrew:

brouw update && brouw phantomjs installeren

Voor Linux-gebruikers is er een 64-bits binair bestand of je hebt een optie om PhantomJS vanaf de bron te compileren.

Na installatie kunt u een terminal openen en controleren of alles in orde is door te draaien:

phantomjs --version

welke zou moeten terugkeren:

1.8.0

Zodra Phantom is geïnstalleerd, kunt u CasperJS ook installeren. Voor Mac-gebruikers kun je Homebrew opnieuw gebruiken:

brouw installeer casperjs

Voor Windows-gebruikers moet u uw toevoegen PAD bestand met "; C: \ casperjs \ batchbin" (Pas dit pad aan, afhankelijk van waar u CasperJS wilt opslaan). Binnen de batchbin map, is er een batchbestand met de naam casperjs.bat, dit is het script dat je Casper-scripts uitvoert zonder dat je Ruby of Python nodig hebt om het uit te voeren. Telkens als u het Casper-script moet uitvoeren, gebruikt u gewoon casperjs.bat scriptnaam.js liever dan casperjs scriptnaam.js.

Controleer vervolgens of:casperjs --version komt terug:1.0.0

Beide versienummers zijn up-to-date vanaf het moment van schrijven van dit artikel.


Hallo PhantomJS

Nu we deze beide hebben uitgevoerd, laten we een paar snelle Hello Worlds doen om ervoor te zorgen dat zowel Phantom als Casper werken zoals verwacht.

Maak een nieuwe map en maak daarbinnen twee JavaScript-bestanden, hellophantom.js en hellocasper.js. Open deze in de editor van uw keuze en laten we beginnen met het controleren of Phantom correct werkt.

We gaan beginnen in de hellophantom.js bestand en schrijf een snelle test om de titel van een webpagina te pakken. Ik ga de PhantomJS API niet in detail bekijken, dit geeft je een korte introductie en test onze installatie. Als PhantomJS al wordt uitgevoerd, kunt u dit gedeelte overslaan.

Eerst moeten we een aantal variabelen instellen, een die de 'webpagina'-module en een andere instantiseert als een' URL'-variabele.

var page = require ('webpagina'). create (), url = "http://net.tutsplus.com";

Vervolgens kunnen we de functie maken die naar de webpagina navigeert, we geven de URL door als een argument en een callback-functie. We ontvangen een status in onze callback (succes of mislukking) op de Open methode.

 page.open (url, functie (status) );

Nu kunnen we de evaluatiefunctie bellen om de titel van de pagina te krijgen. We kunnen het resultaat terugsturen naar een variabele door er de functie aan toe te wijzen:

page.open (url, functie (status) var title = page.evaluate (function () return document.title;););

Ten slotte gaan we dit gewoon uitloggen zodat we het resultaat in de terminal kunnen zien en vervolgens uit het Phantom-proces kunnen stappen.

 console.log ('Hallo, Wereld! De paginatitel op' + url + 'is' + titel); phantom.exit ();

Ons voltooide script zal er ongeveer zo uitzien.

 var page = require ('webpagina'). create (), url = "http://net.tutsplus.com"; page.open (url, functie (status) var title = page.evaluate (function () return document.title;); console.log ('Hallo, Wereld! De paginatitel op' + url + 'is' + titel); phantom.exit (););

CD in de map waar dit script zich bevindt en u kunt het uitvoeren met behulp van de volgende opdracht:

phantomjs hellophantom.js

Na een paar seconden krijgt u het volgende resultaat in uw terminal:

 Hallo Wereld! De paginatitel op http://net.tutsplus.com is zelfstudie voor webontwikkeling, van beginner tot gevorderd | Nettuts+

Dat is geweldig, maar voordat we verder gaan, kunnen we deze code net iets flexibeler maken met een snelle herfactor. Er zijn enkele modules die we kunnen gebruiken en een daarvan is de systeemmodule. Sommige eigenschappen van de systeemmodule geven u toegang tot zaken als de proces-ID die PhantomJS gebruikt of het besturingssysteem dat wordt gebruikt, maar degene waarin wij geïnteresseerd zijn, is de args eigendom.

De args eigenschap retourneert een array van de opdrachtregelargumenten. Het eerste item in de array is altijd de scriptnaam, maar we kunnen een willekeurig aantal argumenten van de opdrachtregel doorgeven en gebruiken in ons script. Dus we kunnen de URL die we willen openen, met fantoom, in de opdrachtregel doorgeven, zodat we het script op elk moment opnieuw kunnen gebruiken zonder het telkens opnieuw te hoeven bewerken.

We moeten eerst eerst de systeemmodule nodig hebben en vervolgens de url variabele om het argument te zijn dat we passeren:

system = require ('system'), url = system.args [1];

en nu kunnen we het script uitvoeren met de volgende opdracht:

phantomjs hellophantom.js http://net.tutsplus.com

Hallo Casper

Nu we weten dat Phantom werkt, kunnen we doorgaan met het testen van Casper. We zullen hetzelfde testscript repliceren, maar deze keer zullen we de Casper API gebruiken.

Eerst moeten we een casperinstantie instantiëren:

var casper = require ("casper"). create ();

en pak dan de URL van een van de argumenten die zijn doorgegeven vanuit de terminal. Casper heeft zijn eigen commandoregel-parser die bovenop die van Phantom zit en we kunnen toegang krijgen tot alle argumenten die vanaf de opdrachtregel worden doorgegeven, net zoals we eerder deden. Het enige verschil is dat ons eerste argument de eerste zal zijn die we passeren en niet de scriptnaam (zoals het was met Phantom)

var url = casper.cli.args [0];

De Casper CLI API kan zowel naamopties als positioneringsargumenten gebruiken, we kunnen dit gebruiken als we enkele opties willen instellen of meer uitgebreid willen zijn met ons script, bijvoorbeeld:

casperjs hellocasper.js argumentOne argumentTwo --option1 = this --option2 = dat

en we kunnen deze benoemde opties gebruiken met cli.get ( 'Optienaam'), dus we zouden iets als het volgende kunnen doen, om zowel argumenten als opties door te geven (als we een aantal configuratie-opties hadden die moesten worden ingesteld):

 var argumentOne = casper.cli.args [0]; var argumentTwo = casper.cli.args [1]; var thisOption = casper.cli.get ('option'); var thatOption = casper.cli.get ('option2');

Voor nu ga ik het positionele argument gebruiken om de URL te krijgen. Vervolgens gaan we het begin() methode om elke soort navigatie uit te voeren. De startmethode neemt een string-URL en een callback-functie.

casper.start (url, function () this.echo ('Hallo, Wereld! De paginatitel op' + url + 'is'););

Als u niet al uw functionaliteit wilt hebben, kunt u de dan() methode. Elk dan() method call wordt toegevoegd als een stap in de stapel en wordt lineair uitgevoerd, dus in plaats van het bovenstaande zou je kunnen hebben:

 casper.start (url); casper.then (function () this.echo ('Hallo, Wereld! De paginatitel op' + url + 'is'););

Ik geef de voorkeur om te gebruiken dan(), omdat ik het gemakkelijker vind om te lezen, maar beide zijn acceptabel en eigenlijk is het allemaal een kwestie van smaak.

Om de titel van de pagina te krijgen is er al een getTitle () methode beschikbaar voor ons, dus we kunnen dat gewoon gebruiken in onze echo.

 casper.start (url); casper.then (function () this.echo ('Hallo, Wereld! De paginatitel op' + url + 'is' + this.getTitle ()););

Eindelijk rennen we onze stappen met de rennen() methode, die een verplichte methode is, nodig om uw Casper-script uit te voeren. Deze methode kan ook een optionele hebben onComplete terugbellen om uit te voeren als alle stappen voltooid zijn. Als u de callback hebt gebruikt, moet u ervoor zorgen dat u het Casper-proces afsluit met behulp van de Uitgang() methode. Hier is een voorbeeld van beide:

 // dit hoeft niet de exit-methode te gebruiken. casper.run (); // OF // dit heeft de exit-methode casper.run (function () this.echo ('Alles in de stapel is afgelopen'); this.exit ();)

Als alternatief kun je de exit-methode na de echo gewoon ketenen:

casper.run (function () this.echo ('Alles in de stapel is afgelopen'). exit ();)

Nogmaals, slechts een kwestie van smaak.

Nu zou ons complete HelloCasper.js-script er als volgt uit moeten zien:

var casper = require ("casper"). create (); var url = casper.cli.args [0]; casper.start (url, function () this.echo ('Hallo, Wereld! De paginatitel op' + url + 'is' + this.getTitle ());); casper.run (function () this.echo ('Alles in de stapel is beëindigd.'). exit (););

We kunnen nu het Casper-script uitvoeren met de volgende opdracht:

casperjs hellocasper.js http://net.tutsplus.com

Het doet niet veel anders dan wat we al deden met Phantom, Casper geeft ons gewoon een leuke API (met wat toegevoegde extra's) om op de top van Phantom te zitten en maakt de code die we schrijven iets uitgebreider en leesbaarder, dit is met name handig wanneer u scripts schrijft die door een site moeten navigeren.

Laten we nu een duik nemen in het opslaan van enkele snapshots van ons scherm.


Basisprincipes van snapshots

Ik begin met een bestand met de naam casperscreens.js en sta Casper voor de gek. Stel vervolgens een array in die de gewenste viewport-breedtes bevat waarmee we schermafbeeldingen willen vastleggen. Elk item in de array zal bestaan ​​uit een andere array die de breedte en hoogte zal hebben die we willen instellen.

viewportSizes = [[320.480], [320.568], [600,1024], [1024.768], [1280.800], [1440.900]]

Ik ga ook een var instellen om de URL van de opdrachtregel te krijgen en dan wil ik een regex op de URL uitvoeren om een ​​map te maken waarin de schermafbeeldingen worden opgeslagen. Ik ga gewoon de http: // deel en vervang de periodes met koppeltekens. Dan gaan we rennen casper.start ().

 saveDir = url.replace (/ [^ a-zA-Z0-9] / gi, '-'). replace (/ ^ https? - + /, "); casper.start ();

Nu gaan we een lus gebruiken en voor elke kijkgrootte een schermafbeelding van de opgegeven URL maken. We gaan de viewport instellen op de groottes die zijn gedefinieerd in het array-item dat we hebben - open de URL - wacht 5000 milliseconden om te zorgen dat de pagina is geladen - en leg vervolgens twee soorten schermafbeeldingen vast.

De eerste is voor de werkelijke hoogte en breedte gedefinieerd, hiervoor gebruiken we de gevangen nemen() methode die twee argumenten vereist: een tekenreeks voor het uitvoerbestand en een objectargument om in te stellen welk deel van de pagina moet worden geknipt. De tweede is voor een complete pagina screenshot met alleen de gedefinieerde breedte en we doen dit met behulp van de captureSelector () methode die het gebied binnen de gedefinieerde selector vangt, in ons geval gebruiken we het gewoon lichaam en deze methode neemt twee argumenten, de eerste is de bestandsnaam en de tweede is de selector.

Hoewel de daadwerkelijk gedefinieerde screenshot nuttig is, heb ik gemerkt dat het ook handig is om een ​​chromide screenshot van volledige pagina te hebben, zodat je kunt zien hoe de hele pagina stroomt.

casper.each (viewportSizes, function (self, viewportSize, i) // stel twee vars in voor de hoogte en breedte van het kijkvenster terwijl we elk item in de viewport-matrix doorlopen var width = viewportSize [0], height = viewportSize [1] ; // geef de pagina wat tijd om casper.wait te laden (5000, function () // stel de viewport in op de gewenste hoogte en breedte this.viewport (width, height); casper.thenOpen (url, function () this.echo ('Opening bij' + breedte); // Stel twee vars in, één voor de volledige pagina opslaan, één voor de werkelijke viewport opslaan var FPfilename = saveDir + '/ fullpage-' + width + ".png"; var ACfilename = saveDir + '/' + width + '-' + height + ".png"; // Capture selector captures the whole body this.captureSelector (FPfilename, 'body'); // capture koppelt een gedefinieerde selectie van de pagina this.capture (ACfilename, top: 0, left: 0, width: width, height: height); this.echo ('snapshot taking'););););

Eindelijk noemen we de rennen() methode en in de callback-functie, ik ga gewoon herhalen dat het vastleggen is voltooid.

casper.run (function () this.echo ('Finished captures for' + url) .exit (););

Het volledige script zou er nu als volgt uit moeten zien:

 var casper = require ("casper"). create (), viewportSizes = [[320,480], [320,568], [600,1024], [1024,768], [1280,800], [1440,900]], url = casper.cli.args [0], saveDir = url.replace (/ [^ a-zA-Z0-9] / gi, '-'). replace (/ ^ https? - + /, "); casper .start (); casper.each (viewportSizes, function (self, viewportSize, i) // stel twee vars in voor de hoogte en breedte van het kijkvenster terwijl we elk item in de viewport-array doorlopen var width = viewportSize [0], height = viewportSize [1]; // geef de pagina wat tijd om casper.wait te laden (5000, function () // stel de viewport in op de gewenste hoogte en breedte this.viewport (width, height); casper.thenOpen ( url, function () this.echo ('Opening bij' + width); // Stel twee vars in, één voor de volledige pagina opslaan, één voor de werkelijke viewport save var FPfilename = saveDir + '/ fullpage-' + width + ".png"; var ACfilename = saveDir + '/' + width + '-' + height + ".png"; // Capture selector captures the whole body this.captureSelector (FPfilename, 'body'); // capture snaps een gedefinieerde selectie o f de pagina this.capture (ACfilename, top: 0, left: 0, width: width, height: height); this.echo ('momentopname gemaakt'); ); ); ); casper.run (function () this.echo ('Finished captures for' + url) .exit (););

En nu kunnen we dit script uitvoeren met de volgende opdracht:

casperjs casperscreens.js http://todomvc.com

Ik heb ervoor gekozen om een ​​aantal schermen van todomvc.com te maken, gewoon omdat het een responsieve site is die het soort resultaten kan weergeven waarnaar we op zoek zijn.

Als u nu naar de map gaat waar het script werd uitgevoerd, ziet u een nieuwe map en binnen zijn al uw PNG's.



Afronden

Dus we zijn erin geslaagd een vrij klein beetje JavaScript te schrijven dat veel gedoe zal besparen, de volgende keer dat de baas of de klant een heleboel screenshots wil, terwijl we ook een aanvullend script kunnen toevoegen aan onze toolbox als we wat testen doen . Natuurlijk laat dit ons alleen een WebKit-weergave zien, maar voor velen is dat goed genoeg.

Probeer dit nu te integreren in uw bouwproces, voer het naast uw andere tests uit en gebruik de schermopnamefunctionaliteit om niet alleen de reactietijd van uw site te testen, maar ook hoe een gebruikersreis er op verschillende grootteschermen uitziet. Bekijk ook de Grunt plug-in grunt-casper als Grunt deel uitmaakt van je bouwproces.

Als je een fan bent van CoffeeScript, kun je zelfs proberen dit script opnieuw te schrijven in de CoffeeScript-syntaxis, zorg er gewoon voor dat je bestand eindigt met de .koffie uitbreiding:

 casperjs casperscreen.coffee http://example.com

En u hoeft zich zelfs geen zorgen te maken over het pre-compileren van uw CoffeeScript-, Casper-scripts.

Er is zoveel meer voor zowel CasperJS als PhantomJS, dus bekijk hun respectieve sites en kijk hoe ze u kunnen helpen met uw testen.