Månadsarkiv: Januari 2014

Stackars mannen cachelagring i JavaScript

[TL;DR version: Använd cookies för att lagra resultaten av async samtal; göra resultaten av tidigare async samtal omedelbart och sedan validera dem efter sidan.]

Jag har jobbat på SharePoint intranät-webbplats för en klient som har, bland annat, en stiliserad sekundär navigering vars menyalternativ hanteras via en vanlig gammal anpassad lista.  Tanken är att klienten får styra "sina" webbplats-menyn utan att påverka eller påverkas av den globala navigeringen som tas ut av det.

(finns det något otroligt omstörtande om att lägga till en CEWP som pekar på en HTML-fil som laddar lite CSS- och JS att i grunden förändra nästan allt om en webbplats beteende... men det är för en annan tjänst)

Koden för denna ganska enkla:

Öm plats här är att varje gång någon träffar en av webbplatsens sidor, användarens webbläsare är att nå ut till få poster i listan.  När dev är komplett och tester har visat att vara stabil och komplett, denna uppmaning är onödigt mer än 99% av tiden eftersom menyn sällan ändras.  Det har också en konstig UI påverka som är vanligt i denna sköna nya värld av hyper-ajaxy webbplatser – sidan återger och först då gör menyn.  Det är skakis och störande i min mening.  Och skakis. Så, cachelagring. 

Jag ändrade logiken thusly:

  • Leta efter cookies i webbläsaren som innehåller menyn när jag senast läste det
    • Om hittade, göra det omedelbart.  Vänta inte på att sidan laddas.  (Du måste se till att din HTML är strategiskt placerad här, men det är inte svårt att göra).
  • Vänta på att sidan laddas och göra en asynkrona anrop till ladda upp menyn objekt från en lista med resten eller lists.asmx eller vad
  • Jämför vad jag fick mot cookie
    • Om det matchar, Stanna
    • Annars, med hjälp av jQuery, dynamiskt fylla ett gäng om <Li>är i en <UL>
  • Använd CSS för att göra all formatering
  • Vinst!

Några av er kommer att säga, "hey! Det finns ingen riktig caching pågår här eftersom du läser menyn ändå varenda gång.”  Och du har rätt – jag tänker inte ge servern någon form av paus.  Men eftersom samtalet är asynkrona och händer efter sidan inledande HTML-nyttolast gör helt, Det känns"" mer lyhörd för användaren.  Menyn gör ganska mycket som sidan drar.  Om menyn händer till förändring, användaren utsätts för en skakis åter dra på menyn, men bara att en gång.

Det finns några sätt att göra detta caching effektivare och hjälpa till servern samtidigt:

  • Sätta i en regel att den "cookie cachen" är giltigt i minst 24 timmar eller några andra tidsram. Så länge det finns ingen utgångna cookie, Använd Kakans menyn ögonblicksbild och aldrig träffa servern.

Tja... det är allt som kommer att tänka på just nu :). 

Om någon har några smarta idéer här skulle jag älska att veta dem.

Och slutligen – denna teknik kan användas för andra saker.  Denna klient sidan har ett antal datadrivna saker på olika sidor, många av dem ändra förhållandevis sällan (som en gång i veckan eller en gång i månaden).  Om du riktar särskilda områden av funktioner, Du kan ge en mer lyhörd UI genom att dra innehåll från lokala cookie butik och rendering omedelbart.  Det känns snabbare att användaren även om du inte sparar servern alla cykler.  Du kan Spara server cykler genom beslut på vissa villkor och utlösare att ogiltigförklara denna lokala cookie cache.  Det är alla situationsanpassat och konstnärliga saker och verkligen den roligaste :). 

</slutet>

undefinedPrenumerera på min blogg.

Följ mig på Twitter vid http://www.twitter.com/pagalvin

Hur: Konfigurera enhetstest och testa täckning med QUnit.js och Blanket.js för kontor 365 SharePoint App

Intro

Jag har utforskat enhetstestning och testa täckning för JavaScript som jag arbetar på en ny SharePoint-app för SharePoint online i Office 365 svit.  De uppenbara forskning vägar ledde mig till Qunit.js och direkt efter att, till Blanket.js.

QUnit Låt mig ställa in enhetstester och gruppera dem i moduler.  En modul är bara ett enkelt sätt att organisera relaterade tester. (Jag vet inte om jag använder det som avsett, men det fungerar för mig hittills med liten uppsättning tester som jag hittills har definierat).

Blanket.js integreras med Qunit och det kommer Visa mig de faktiska rader JavaScript som var – och ännu viktigare-inte faktiskt avrättades under kör testerna.  Detta är "täckning"-rader som avrättades omfattas av testet medan andra inte är.

Mellan att ställa in bra testfall och Visa täckning, Vi kan minska risken att vår kod har dolda defekter.  Goda tider.

Qunit

Förutsatt att du har din Visual Studio projektet skapa, börja med att ladda ner JavaScript paketet från http://qunitjs.com.  Lägga till JavaScript och motsvarande CSS i din lösning.  Mine ser ut såhär:

image

Figur 1

Som ni kan se, Jag var med 1.13.0 på tiden skrev jag detta blogginlägg. Glöm inte att hämta och lägga till CSS-filen.

Som ur vägen, Nästa steg är att skapa något slags test sele och referera de Qunit bitarna.  Jag testar en massa funktioner i en skriptfil som kallas "QuizUtil.js" så jag skapade en HTML-sida som kallas "QuizUtil_test.html" som visas:

image Figur 2

Här är koden:

<!DOCTYPE HTML>
<HTML xmlns= "http-://www.w3.org/ 1999/xhtml">
<huvud>
    <titel>QuizUtil test med Qunit</titel>
    <länk rel= "stylesheet" href="../CSS/qunit-1.13.0.CSS" />
    <skript typ= text/javascript"" src="QuizUtil.js" data-cover></skript>
    <script typ ="text/javascript" src ="qunit-1.13.0.js"></skript>
    <script typ ="text/javascript" src ="blanket.min.js"></skript>

    <skript>
        modul("getIDFromLookup");
        Testa("QuizUtil getIDFromLookupField", funktionen () {
            var goodValue = "1;#Paul Galvin";

            lika(getIDFromLookupField(goodValue) + 1, 2), "ID för [" + goodValue + "] + 1 bör vara 2";
            lika(getIDFromLookupField(undefined), undefined, "Odefinierad indataargumentet bör återvända odefinierat resultatet.");
            lika(getIDFromLookupField(""), undefined, "Tom indataargumentet ska returnera ett odefinierat värde.");
            lika(getIDFromLookupField("gobbledigood3-thq;dkvn ada;skfja sdjfbvubvqrubqer0873407t534piutheqw;vn"), undefined,"Ska alltid returnera ett resultat Cabriolet till ett heltal");
            lika(getIDFromLookupField("2;#någon annan person"), "2", "Kontrollera [2;#någon annan person].");
            lika(getIDFromLookupField("9834524;#lång värde"), "9834524", "Stort värde test.");
            notEqual(getIDFromLookupField("5;#någon", 6), 6, "Testa en notEqual (5 är inte lika med 6 för detta prov: [5;#någon]");

        });

        modul("htmlEscape");
        Testa("QuizUtil htmlEscape()", funktionen () {
            lika(htmlEscape("<"), "&LT;", "Fly en mindre än-operator ('<')");
            lika(htmlEscape("<div class =  "someclass">Lite text</div>"), "&LT;div class =&quot;someclass&quot;&gt;Lite text&LT;/div&gt;", "Mer komplex test sträng.");
        });

        modul("getDateAsCaml");
        Testa("QuizUtil getDateAsCaml()", funktionen () {
            lika(getDateAsCaml(nya Datum("12/31/2013")), "2013-12-31T:00:00:00", "Testa hårdkodade datum: [12/31/2013]");
            lika(getDateAsCaml(nya Datum("01/05/2014")), "2014-01-05T:00:00:00", "Testa hårdkodade datum: [01/05/2014]");
            lika(getDateAsCaml(nya Datum("01/31/2014")), "2014-01-31T:00:00:00", "Testa hårdkodade datum: [01/31/2014]");
            lika(getTodayAsCaml(), getDateAsCaml(nya Datum()), "getTodayAsCaml() ska vara lika getDateAsCaml(nytt datum())");
            lika(getDateAsCaml("nonsens värde"), undefined, "Försöka få datum för ett nonsens värde.");
            lika(getDateAsCaml(undefined), undefined, "Försöka få datum för den [undefined] datum.");
        });

        modul("getParameterByName");
        Testa("QuizUtil getParameterByName (från frågesträngen)", funktionen () {
            lika(getParameterByName(undefined), undefined, "Försöka få odefinierad parameter bör återvända odefinierat.");
            lika(getParameterByName("finns inte"), undefined, "Försöka få parametervärde när vi vet att parametern inte finns.");

        });

        modul("Cookies");
        Testa("QuizUtil olika cookie funktioner.", funktionen () {
            lika(setCookie("test", "1", -1), getCookieValue("test"), "Få en cookie som jag ska fungera.");
            lika(setCookie("anycookie", "1", -1), sant, "Ange en giltig matlagning ska returnera 'true'.");
            lika(setCookie("crazy cookie-namn !@#$%"%\^&*(()?/><.,", "1", -1), sant, "Ställa in en dålig cookie-namn ska returnera"falska".");
            lika(setCookie(undefined, "1", -1), undefined, "Passerar odefinierat som namnet på cookie.");
            lika(getCookieValue("finns inte"), "", "Cookie finns inte testet.");
        });

    </skript>
</huvud>
<organ>
    <div ID= "qunit"></div>
    <div ID= "qunit-fixtur"></div>

</organ>
</HTML>

Det finns flera saker som händer här:

  1. Referera till min kod (QuizUtil.js)
  2. Referenser Qunity.js
  3. Definiera några moduler (getIDFromLookup, Cookies, och andra)
  4. Att placera en <div> vars ID är "qunit".

Sedan, Jag dra bara upp denna sida och du får något sådant:

image

Figur 3

Om du tittar överst, har du några alternativ, varav två är intressant:

  • Dölj klarat tester: Ganska uppenbart.  Kan hjälpa ögat bara se problemområden och inte en massa skräp.
  • Modul: (släpp ner): Detta kommer att filtrera testerna till just dessa grupper av tester som du vill.

När det gäller testerna själva-några kommentarer:

  • Det säger sig självt att du måste skriva din kod så att det är testbara i första hand.  Med hjälp av verktyget kan hjälpa till att upprätthålla den disciplinen. Till exempel, Jag hade en funktion som kallas "getTodayAsCaml()”.  Detta är inte mycket testbara eftersom det tar ingen indataargumentet och testa det för jämställdhet, Vi skulle behöva ständigt uppdatera Provningsmetod för att återspegla det aktuella datumet.  Jag refactored det genom att lägga till en indataparameter för data sedan passerar det aktuella datumet när jag vill ha dagens datum i CAML-format.
  • Ramen Qunit dokumenterar sina egna tester och det verkar ganska robust.  Det kan göra enkla saker som att testa för jämställdhet och har även stöd för ajax stil samtal (både "riktiga" eller hånade med din favorit knäcka).
  • Gå igenom processen också tvingar dig att tänka igenom kant fall – vad händer med "odefinierade" eller null överförs till en funktion.  Det gör att det är död enkel att testa dessa scenarier ut.  Bra grejer.

Täckning med Blanket.js

Blanket.js kompletterar Qunit genom att spåra de faktiska kodrader som kör under köra dina tester.  Det integrerar rätt in i Qunit så även om det är en helt separat app, Det leker fint-det ser verkligen ut som det är en smidig app.

Detta är blanket.js i aktion:

image Figur 4

image

Figur 5

(Du måste faktiskt Klicka på kryssrutan "Aktivera täckning" överst [se figur 3] att möjliggöra detta.)

Markerade rader i figur 5 har inte utförts av någon av mina tester, så jag behöver att utforma ett test som orsakar dem att köra om jag vill ha full täckning.

Få blanket.js fungerar på följande sätt:

  1. Ladda ner från http://blanketjs.org/.
  2. Lägg till det i projektet
  3. Uppdatera din sele testsida (QuizUtil_test.html i mitt fall) enligt följande:
    1. Referens koden
    2. Dekorera din <skript> referens gillar detta:
    <skript typ= text/javascript"" src="QuizUtil.js" data-cover></skript>

Blanket.js plockar upp attributet "data-cover" och gör sin magi.  Det krokar i Qunit, uppdateringar av UI för att lägga till alternativet "Aktivera täckning" och voila!

Sammanfattning (TL; DR)

Använda Qunit för att skriva din testfall.

  • Ladda ner den
  • Lägg till det i projektet
  • Skriva en testsida sele
  • Skapa dina tester
    • Refactor några av din kod vara testbara
    • Vara kreativ!  Tror galen, omöjligt scenarier och testa dem ändå.

Använd blanket.js för att säkerställa täckning

  • Kontrollera att Qunit fungerar
  • Hämta blanket.js och lägga till ditt projekt
  • Lägga till din sele testsida:
    • Lägg till en hänvisning till blanket.js
    • Lägga till en "data-cover" attribut till din <skript> tag
  • Köra din Qunit tester.

Jag aldrig gjorde något av detta innan och hade några elementära saker som arbetar i en handfull timmar. 

Glad testning!

</slutet>

undefinedPrenumerera på min blogg.

Följ mig på Twitter vid http://www.twitter.com/pagalvin