COSC2759 :linting and unit tests Lab Assessment
COSC2759Lab/TutorialWeek4(2023)
Goalsofthislab
- Buildonexperiencefromweek3slab(GitHubActions)andincorporateknowledgefromweek4slab(automatedtesting).
- In this lab well cover linting and unit tests. A full CI pipeline (e.g. for assignment 1)wouldincludeadditionaljobs,butyoucanstarttoseeapatternforyoutofollowtofilloutthose
Createyourselfatestrepoforthislab,andcloneit
- Log in to GitHub in a web browser, and create a repo under your account. Call itanything,g.`lab4-test`.UndertheheadingInitializethisrepositorywithtickAddaREADMEfile.
- Findthesshurlofyournewrepo,itwilllooksomethinglike
`git@github.com:john-doe/lab4-test.git`.
- Clonetherepowith`gitclone
`and`cd`intothereposworking - PerhapsmakesomechangetotheREADMEfileandpushthemuptoGitHub(viewthem in the GitHub portal) to check you remember how to use git and have it set up(Youcanlookatthelab3notesandthegitcyclevideosformoretips.)
Createafeaturebranch
- InthislabweregoingtocreateaGitHubActionsCICreateanewfeaturebranch`gitcheckout-bfeature/add-pipeline`.
- PushthenewbranchuptoItwillhavetheexactsamecommitsasmain,butpush it up anyway just as a starting point. (Refer to lab 3 notes for detailedinstructionsifrequired.)
Fillinthesampleapp
YoucanthaveaCIpipelinewithoutanapp.Wewanttokeepthingssimplesowelluseadummyappthatjustaddstwonumberstogether.
- Create`sum.js`withthefollowingcontents:
functionsum(a,b){returna+b;
}
module.exports=sum;
- Create`sum.test.js`withthefollowingcontents:
constsum=require('./sum');
test('adds1+2toequal3',()=>{expect(sum(1,2)).toBe(3);
});
test('adds3+4toequal7',()=>{expect(sum(3,4)).toBe(7);
});
- Create`package.json`withthefollowingcontents:
{
"name":"lab-4-demo",
"version":"1.0.0",
"description":"",
"main":"sum.js","scripts":{
"lint":"eslint.",
"test-unit":"jest"
},
"keywords":[],
"author":"",
"license":"","devDependencies":{
"eslint":"^8.11.0",
"jest":"^27.5.1",
"jest-junit":"^13.0.0"
}
}
- Create`.eslintrc.yml`withthefollowingcontents:
env:
node:truecommonjs:truees6:truejest:true
extends:
-eslint:recommendedglobals:
Atomics:readonlySharedArrayBuffer:readonly
parserOptions:ecmaVersion:2018
rules:
no-trailing-spaces:"error"
- Create`jest.config.js`withthefollowingcontents:
module.exports={reporters:[
'default',
['jest-junit',{outputDirectory:'reports',outputName:'report.xml'}],
],
};
- Finallycreate`.gitignore`withthefollowingcontents:
node_modulesreports
Thiswillensureyoudontpushyourlocalcopyofdependenciesortestreportsintotherepotheydontbelongintherepo.
- Run`npminstall`.Thenhavealookatthe`node_modules`Whatdoes
`npminstall`do?
- Notethatwedidntrun`npminit`.Whatdoes`npminit`do?
Createthepipelineandaddlinting
- FirstwewillrunthelinterRun`npmrunlint`.Whatdoesthisdo?Howdoes
`npm`knowwhattodowhenyoutellittorunlint?
- NextweaddthisjobtotheCIInyourrepo,createthefile
`.github/workflows/ci-pipeline.yml`withthefollowingcontents:
name:Lab4CIPipelineon:
push:
branches:
- mainpull_request:
branches:
- mainjobs:
lint:
runs-on:ubuntu-lateststeps:
- uses:actions/checkout@v3
- name:Usejs18.xuses:actions/setup-node@v3with:
node-version:"18"
- name:Installdependenciesrun:npmclean-install
- name:Runlinterrun:npmrunlint
This creates a pipeline with a single job, called lint. The lint job contains severalsteps.Withineachjob,youhavetoinstalltoolssuchasnode,andyouhavetoinstallyourdependencies.EachjobshouldbeassumedtorunonanewVM,soinstallyourtoolsineveryjob,andpushartifactswithinthejobtoo.
- Use`gitadd`,`gitcommit`and`gitpush`topackageupyourchangesandcopythemupto
- GototheGitHubActionstabandwatchthepipeline
- Ifitfails,debug:-)
Unittesting
- FirstwewillruntheunittestsRun`npmruntest-unit`.(Doyounoticeapatternbetweenthissectionandtheprevioussection?)
- NextweaddthisjobtotheCIIn`.github/workflows/ci-pipeline.yml`,addajobtotheexistingjobssectionontotheend(carefulwiththeindentation):
unit-tests:
runs-on:ubuntu-lateststeps:
- uses:actions/checkout@v3
- name:Usejs18.xuses:actions/setup-node@v3with:
node-version:"18"
- name:Installdependenciesrun:npmclean-install
- name:Rununittestsrun:npmruntest-unit
- if:success()||failure()
uses:actions/upload-artifact@v3with:
name:unit-test-${{github.sha}}path:reports/report.xml
Note that we tell GitHub Actions to upload the artifact regardless of successorfailureintheprecedingsteps.Bydefault,pipelinesbailonthefirstsignoftrouble; this is usually what you want. But with things like test reports, youwant to override that default and stash the report telling you about the testfailures. (Of course if your unit tests fail them you dont want to go on to runintegration tests or end-to-end tests. Just bail and give that feedback to thedeveloperASAP.)
- Use`gitadd`,`gitcommit`and`gitpush`topackageupyourchangesandcopythemupto
- Go to the GitHub Actions tab and watch the pipeline run. You might notice that thelinterandunittestsruninIsthiswhatwewant?Laterinthelabwewilllearnhowtoinsertdependencyrelationshipstoforcejobstoruninaparticularsequence.
- Ifitfails,debug:-)
- Canyoufindthetestreportartifact?
Disablingjobsinapipeline
- Editthelintjobtoaddanif:falseproperty,likeso:
lint:
if:false
runs-on:ubuntu-lateststeps:
- uses:actions/checkout@v3
- name:Usejs18.xuses:actions/setup-node@v3with:
node-version:"18"
- name:Installdependenciesrun:npmclean-install
- name:Runlinterrun:npmrunlint
- Use`gitadd`,`gitcommit`and`gitpush`topackageupyourchangesandcopythemupto
- GototheGitHubActionstabandwatchthepipelineWhathappenedtothelintjob?
- Thinkaboutwhatotherconditionsyoumightputintotheifpropertytocontrolyourpipeline
- Beforemovingon,revertthechangeyoumadetodisablethelint(Ifyoudiditas a separate commit, you can `git revert` which is handy.) Were removing thedisabling. Double negatives. Wow. Can I make that more confusing? Recursion!Summary:wewantthelintertostartrunningagain!:-)
Makingajobdependentonanother
- Maketheunittestsdependentonthelinterbyaddinganeeds:lintpropertytotheunittestjob,likeso:
unit-tests:
needs:lint
runs-on:ubuntu-lateststeps:
- uses:actions/checkout@v3
- name:Usejs18.xuses:actions/setup-node@v3with:
node-version:"18"
- name:Installdependenciesrun:npmclean-install
- name:Rununittestsrun:npmruntest-unit
- if:success()||failure()
uses:actions/upload-artifact@v3with:
name:unit-test-${{github.sha}}path:reports/report.xml
- Use`gitadd`,`gitcommit`and`gitpush`topackageupyourchangesandcopythemupto
- GototheGitHubActionstabandwatchthepipelineHowdoesthispipelinerunlookdifferenttopreviousruns?
Failurescenarios
- Canyoumakethelinterfailinthepipeline,justbychanging`sum.js`?
- Canyoumaketheunittestsfailinthepipeline,justbychanging`sum.js`?
- CanyoucrashGitHubActionsandgetrootonaproductionserverinsideMicrosoft?(OK this last one is a joke, before you do anything like that please seehttps://bounty.github.com/#rules)