Testen van je JavaScript: Jurassic!

Ingediend door Dirk Hornstra op 17-feb-2025 19:33

Er was een probleem met de tinyMCE-editor in de backoffice van Umbraco, wat er aan de hand was (en hoe ik het gefixt heb) kun je in deze 2 blog-artikelen teruglezen: artikel 1, artikel 2.

Op mijn laptop heb ik Visual Studio, hiermee startte ik een Umbraco-omgeving op, logde ik in op de backoffice. Vervolgens ging ik naar een pagina, klikte daarin de tinyMCE editor en op de plaats in de tekst waar de macro geplaatst moest worden, klikte ik op de "macro invoegen knop". Dan selecteerde ik wat ingevoegd moest worden, klikte op invoegen en vervolgens werd  mijn script uitgevoerd. Dan gaat er iets niet goed, ik pas de code aan in Visual Studio, ga vervolgens terug naar de browser, herlaadt het scherm en doe dezelfde stappen opnieuw.

Naast het feit dat dit niet optimaal is (het opstarten van Umbraco duurt gauw 20 tot 30 seconden) test ik hier ook maar 1 scenario. Ik heb nog wat andere teksten waar ik dit ook in wil testen. De code die ik gebouwd had, had ik eerst "werkend" gemaakt. Dat betekent dat de werking (nog) niet optimaal is. Hierna wil je gaan schaven aan je code om overbodige zaken eruit te kunnen halen en mogelijk om "de flow" anders te bouwen, zodat je hoeveelheid code minimaal is en ook de mogelijkheid dat er "iets fout gaat" zo laag mogelijk is.

Ik heb ervaring met testen. In Visual Studio voeg ik bij mijn project een nieuw project toe van type "Xunit". Als ik een nuget-package bouw, dan probeer ik elke functie "testbaar" te maken. Zo kun je met een gerust hart aanpassingen doorvoeren en ook zo nu en dan controleren of de externe code waar jouw applicatie op gebaseerd is nog op dezelfde manier werkt en je een goed resultaat geeft. Dat wil ik dus hier ook. Hoe kan ik ervoor zorgen dat ik mijn JavaScript-code kan testen in Visual Studio?

Als je artikel 2 gelezen hebt weet je het antwoord al: Jurassic! In een podcast van Scott Hanselman (Hanselminutes 277), gemaakt in 2011 wordt deze tool genoemd. 

 

Eerste poging

Je kunt dit toevoegen in je C# project om JavaScript uit te voeren. Ik kan natuurlijk niet mijn volledige code daar "in" gooien, want daar zitten verwijzingen in naar onder andere Angular en tinyMCE, zaken die binnen de backoffice van Umbraco draaien, maar waarop Jurassic gaat zeggen: "unknown variables" of iets dergelijks. Geen probleem, want dat wil ik ook niet testen. Ik wil mijn code testen die de originele tekst vergelijkt met de nieuwe tekst, daaruit kan halen waar de macro ingevoegd is en vervolgens de paragrafen die daarom heen geplaatst zijn "eruit halen", zodat je een goed resultaat overhoudt.

Ik begin met ongeveer 130 regels code. Ik voeg 3 submappen in mijn "examples"-map toe met daarin 3 bestanden, de originele content, de gewijzigde content en de content die ik verwacht te krijgen als alles goed gaat. Na het inrichten van de testcode (ongeveer een half uurtje werk) kan ik deze 3 voorbeelden met 3 regels code valideren. Ik krijg 3 groene bolletjes, de testen lukken. Vervolgens ga ik de code refactoren, zaken samenvoegen, functies toevoegen om te voldoen aan het principe dat "een functie maar 1 ding mag doen". Zo hou ik een tijdje rode bolletjes (testen falen), maar aan het eind van de avond heb ik ze alle 3 weer groen. De code bestaat inmiddels uit 73 regels.

De volgende dag krijg ik een heldere ingeving. Want wat ik nu doe is dat ik bij de BeforeSetContent-functie detecteer of we een macro gaan invoegen, zo ja, dan ga ik in de SetContent-functie in de tekst zoeken naar de plaats waar die macro geplaatst is, zodat ik de omringende lege paragrafen kan weghalen. Maar... ik kan in de BeforeSetContent-functie de content zelf nog aanpassen! Ik zou er dus een stuk commentaar voor <!-- INSERT MACRO UNIEKEWAARDE: START --> en erachter <!-- INSERT MACRO UNIEKEWAARDE: EINDE --> kunnen plaatsen. Dan hoef ik in de SetContent-functie niet door de hele tekst heen te zoeken, ik hoef "alleen maar" op deze teksten te zoeken om de locatie te vinden. De 20 regels code die ik daarvoor nodig heb zou ik dan misschien nog kunnen halveren.

 

Tweede poging

Ik heb de bovenstaande fix doorgevoerd en daardoor kan ik sneller de locatie in de HTML vinden waar we de macro invoegen en kan ik vervolgens de andere plaatsen "rondom dit punt" bepalen, zodat ik alles eruit kan filteren.

Maar ik ga het even "iets anders aanpakken". Wat ik namelijk deed was de functionaliteit testen en dan "de werkende code" terug zetten in een stuk javascript waar ook de Umbraco-Angular zaken in stonden. Dat splitsen, daar ben ik op teruggekomen. Ik wil eigenlijk exact hetzelfde bestand testen wat ik ook als plug-in in Umbraco gebruik. Copy-paste. Dat zorgt namelijk dat ik bij aanpassingen het in mijn testproject kan aanpassen, net zolang de code aanpas tot al mijn testen groene bolletjes terug geven en dan het javascript-bestand weer in mijn Umbraco-installatie toevoegen.

Zoals je op de pagina van Jurassic terug kan lezen wordt nog niet alles ondersteund (scroll even naar beneden, ECMAScript 6 status). In mijn eerste code gebruikte ik "static" classes en deed ik iets met een setTimeout: die statements waren niet geldig in de parser van Jurassic. Ik heb mijn code dus aangepast zodat deze door Jurassic geaccepteerd wordt.

Het test-project: Github - Jurassic test included

Ik heb een losse branch toegevoegd waarin je kunt zien hoe mijn testcode werkt;

 

De basis is tinymce.paragraphformacro.remover.js. Je ziet onderaan dat er een app.run uitgevoerd wordt en in de code worden zaken met de tinymce-instantie en de editors gedaan. Daarvoor heb ik /scripts/script-pre.js toegevoegd. Daarin maak ik een soort "dummy-classes"  aan, zodat de aanroepen in het script door Jurassic als "geldige/uitvoerbare" code beschouwd worden.

Vervolgens wil je een aantal scenario's testen. Je geeft de macro en de invoer-tekst (met de plaats waar de macro moet komen) door. Dat doen we aan het begin van de code en zie je terug in /Models/JurassicTestModel.cs met de variabelen "initialContent" en "ourMacroToInsert". In /scripts/script-post.js zie je dat we vervolgens gaan "faken" alsof we de insert-macro-knop ingedrukt hebben en de macro in onze tekst toevoegen.

In mijn eerste poging voerde ik _engine.Evaluate() uit, maar die functie is eigenlijk alleen geschikt om kort reken-acties uit te voeren. Ik kreeg wat onverwachte resultaten terug. Daarom doe ik een _engine.Execute(script) om de code uit te voeren. Het "coole" van Jurassic is dat je met _engine.GetGlobalValue<T>(naam-van-variabele) de waarde van een variabele op kunt vragen. En zo vraag ik de waarde op van variabele outputResult op die ik in het javascript vul met de uiteindelijke HTML. Die kan ik in C# vervolgens vergelijken met mijn "verwachte output" en via een Assert.True(model.Validate()) laten zorgen voor een rood of groen bolletje!

 

Disclaimer

In deze set-up krijg ik niet helemaal wat er "echt" gebeurt in de code. Ik zie namelijk in Umbraco dat als ik dat commentaar ervoor en erachter zet die <!-- INSERT MACRO UNIEKEWAARDE: START --> binnen een <p>...</p> komt te staan. En ik zag ook nog ergens iets met een <br dummy-oid/> binnen de omliggende <p> en </p>. Maar... ik had wel een idee hoe ik dat kon fixen, namelijk op een iets andere manier de locatie van de voorgaande en opvolgende HTML-tags bepalen. Dat vervolgens mijn testen groene vinkjes blijven geven na deze aanpassing geven mij het vertrouwen dat dit een goede/werkende aanpassing is.

 

Conclusie

Hiermee heb ik voor nu een "versie 1.0" van deze javascript-plug-in opgeleverd. Mocht je javascript moeten testen, dan kan Jurassic een optie zijn. Ik hoop dat je op basis van mijn voorbeelden en uitleg je toolkit kunt uitbreiden met Jurassic om je code (extra) testbaar te maken!