<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Dev Blog]]></title><description><![CDATA[Dev Blog.]]></description><link>https://johnhorner.uk/</link><image><url>https://johnhorner.uk/favicon.png</url><title>Dev Blog</title><link>https://johnhorner.uk/</link></image><generator>Ghost 5.1</generator><lastBuildDate>Mon, 08 May 2023 16:35:30 GMT</lastBuildDate><atom:link href="https://johnhorner.uk/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Adding an Atom feed to your Ghost Blog]]></title><description><![CDATA[<p>It&apos;s easy to add custom pages to your favourite Ghost blog theme, and using Ghosts contexts we can leverage author and post data to create an Atom feed to compliment the built in RSS feed that comes with Ghost out of the box.</p><p>All you&apos;ll need</p>]]></description><link>https://johnhorner.uk/adding-an-atom-feed-to-your-ghost-blog/</link><guid isPermaLink="false">62a215f726f19300015d22ed</guid><category><![CDATA[ghost]]></category><category><![CDATA[blog]]></category><category><![CDATA[atom]]></category><dc:creator><![CDATA[John Horner]]></dc:creator><pubDate>Thu, 09 Jun 2022 16:03:37 GMT</pubDate><content:encoded><![CDATA[<p>It&apos;s easy to add custom pages to your favourite Ghost blog theme, and using Ghosts contexts we can leverage author and post data to create an Atom feed to compliment the built in RSS feed that comes with Ghost out of the box.</p><p>All you&apos;ll need to do is take the atom.hbs file from the repo below, unzip your theme file, add the atom.hbs file to the root of the theme and zip it up again. Then for the routing and header injection, just follow the instructions in the repo.</p><p><a href="https://github.com/JWHorner/ghost-atom-feed">https://github.com/JWHorner/ghost-atom-feed</a></p><p>Mark-up <a href="https://validator.w3.org/feed/check.cgi?url=https%3A%2F%2Fjohnhorner.uk/atom/">validated</a> as of time of publishing. Let me know if you spot any validation failures in your feeds &#x1F609;</p>]]></content:encoded></item><item><title><![CDATA[Automating API Testing with Postman, Newman and DevOps Pipelines]]></title><description><![CDATA[<p>So you&apos;ve written an API test suite in Postman with <a href="https://johnhorner.uk/clean-up-your-test-names-in-postman">excellent test naming conventions</a>.</p><p>It&apos;s time to get DevOps to do the rest of the hard work for you and schedule nightly or weekly runs of your tests.</p><p>Firstly, you&apos;ll need to export your</p>]]></description><link>https://johnhorner.uk/automating-api-testing-with-postman-newman-and-devops-pipelines/</link><guid isPermaLink="false">62a0df984b66170001ce1148</guid><category><![CDATA[testing]]></category><category><![CDATA[postman]]></category><category><![CDATA[newman]]></category><category><![CDATA[devops]]></category><dc:creator><![CDATA[John Horner]]></dc:creator><pubDate>Wed, 08 Jun 2022 19:48:01 GMT</pubDate><content:encoded><![CDATA[<p>So you&apos;ve written an API test suite in Postman with <a href="https://johnhorner.uk/clean-up-your-test-names-in-postman">excellent test naming conventions</a>.</p><p>It&apos;s time to get DevOps to do the rest of the hard work for you and schedule nightly or weekly runs of your tests.</p><p>Firstly, you&apos;ll need to export your test suite as JSON as well as the environment and global JSONs. Open up your favourite text editor and change all the environment and global variable values to tokens using __{variable_name}__ (double-underscores):</p><figure class="kg-card kg-code-card"><pre><code class="language-json">{
	&quot;id&quot;: &quot;c2064aba-2c4d-4b8b-b025-c81af835798a&quot;,
	&quot;name&quot;: &quot;Contact API Production&quot;,
	&quot;values&quot;: [
		{
			&quot;key&quot;: &quot;url&quot;,
			&quot;value&quot;: &quot;__ApiUrl__&quot;,
			&quot;type&quot;: &quot;default&quot;,
			&quot;enabled&quot;: true
		},
		{
			&quot;key&quot;: &quot;companySearchTerm&quot;,
			&quot;value&quot;: &quot;__CompanySearchTerm__&quot;,
			&quot;type&quot;: &quot;default&quot;,
			&quot;enabled&quot;: true
		},
		{
			&quot;key&quot;: &quot;companyId&quot;,
			&quot;value&quot;: &quot;__CompanyId__&quot;,
			&quot;type&quot;: &quot;default&quot;,
			&quot;enabled&quot;: true
		}
	],
	&quot;_postman_variable_scope&quot;: &quot;environment&quot;,
	&quot;_postman_exported_at&quot;: &quot;2022-05-24T13:42:02.825Z&quot;,
	&quot;_postman_exported_using&quot;: &quot;Postman/9.18.2&quot;
}</code></pre><figcaption>Contact API Production.postman_environment.json</figcaption></figure><figure class="kg-card kg-code-card"><pre><code class="language-json">{
	&quot;id&quot;: &quot;6fcc71a9-8e5a-4431-86bb-0bd426788177&quot;,
	&quot;values&quot;: [
		{
			&quot;key&quot;: &quot;username&quot;,
			&quot;value&quot;: &quot;__Username__&quot;,
			&quot;type&quot;: &quot;default&quot;,
			&quot;enabled&quot;: true
		},
		{
			&quot;key&quot;: &quot;password&quot;,
			&quot;value&quot;: &quot;__Password__&quot;,
			&quot;type&quot;: &quot;secret&quot;,
			&quot;enabled&quot;: true
		}
	],
	&quot;name&quot;: &quot;Globals&quot;,
	&quot;_postman_variable_scope&quot;: &quot;globals&quot;,
	&quot;_postman_exported_at&quot;: &quot;2022-05-23T11:01:16.517Z&quot;,
	&quot;_postman_exported_using&quot;: &quot;Postman/9.18.2&quot;
}</code></pre><figcaption>workspace.postman_globals.json</figcaption></figure><p>And upload all of these files to a DevOps repo. Now we need a new build pipeline, so create one. I like the classic pipeline editor, but a YAML example is below.</p><p>The first build step is to use the &quot;Replace Tokens&quot; task to fill our environment and global JSON files with the correct settings for this environment. The &quot;Target Files&quot; should be:</p><pre><code>**/*_environment.json
**/*_globals.json</code></pre><p>And the &quot;Token Pattern&quot;</p><pre><code>__...___</code></pre><p>The 2nd step is to install Newman using the &quot;npm&quot; task. Change the &quot;Command&quot; to &quot;Custom&quot; and the &quot;Command and arguments&quot; to:</p><pre><code>install -g newman</code></pre><p>The 3rd task is &quot;Command line&quot;.</p><pre><code class="language-powershell">newman run &quot;$(Build.SourcesDirectory)\Contact API\CE Connector.postman_collection.json&quot; -e &quot;$(Build.SourcesDirectory)\Contact API\Contact API.postman_environment.json&quot; -g &quot;$(Build.SourcesDirectory)\workspace.postman_globals.json&quot; -x -r junit --reporter-junit-export &quot;$(build.artifactstagingdirectory)\Results\Contact API.xml&quot; --insecure</code></pre><p>This is Newman running your tests from the CLI. The first parameter is the test export JSON, the <code>-e</code> parameter is the environment variable export JSON, and the <code>-g</code> &#xA0;parameter is the global variable export JSON.</p><p><code>-x</code> finishes the test suite even in the event of an exception, and we use <code>junit</code> to define the results file.</p><p>The 4th step is &quot;Publish Test Results&quot;. Change the &quot;Test result format&quot; to <code>JUnit</code>, the &quot;Test results files&quot; pattern to <code>**/*.xml</code> and the &quot;Search folder&quot; to <code>$(build.artifactstagingdirectory)</code>.</p><p>That&apos;s it! Change the pipline triggers to whatever schedule you want, and each run will publish the results in the run. Of course, you probably want some reporting on these so you don&apos;t have to go hunting down the release each time it runs, so we&apos;ll add a 5th step - &quot;Email Report&quot;. Set whatever recipients and options you want in here, with the &quot;Email Subject&quot; of:</p><pre><code>[{environmentStatus}] {passPercentage} tests passed for Contact API on build $(Build.BuildNumber)</code></pre><p><code>environmentStatus</code> and <code>passPercentage</code> are built-in properties of the task.</p><p>Here&apos;s the YAML for the whole pipleline described above.</p><pre><code>pool:
  name: On Premise
  demands: npm

steps:
- task: qetza.replacetokens.replacetokens-task.replacetokens@5
  displayName: &apos;Inject variables&apos;
  inputs:
    targetFiles: |
     **/*_environment.json
     **/*_globals.json
    tokenPattern: rm

- task: Npm@1
  displayName: &apos;Install Newman&apos;
  inputs:
    command: custom
    verbose: false
    customCommand: &apos;install -g newman&apos;

- script: &apos;newman run &quot;$(Build.SourcesDirectory)\Contact API Production.postman_collection.json&quot; -e &quot;$(Build.SourcesDirectory)\Contact API Production.postman_environment.json&quot; -g &quot;$(Build.SourcesDirectory)\workspace.postman_globals.json&quot; -x -r junit --reporter-junit-export &quot;$(build.artifactstagingdirectory)\Results\Results.xml&quot; --insecure&apos;
  displayName: &apos;Run Contact API Production tests&apos;

- task: PublishTestResults@2
  displayName: &apos;Publish test results&apos;
  inputs:
    testResultsFiles: &apos;**/*.xml&apos;
    searchFolder: &apos;$(build.artifactstagingdirectory)&apos;

- task: epsteam.EmailReportExtension.EmailReport.EmailReport@1
  displayName: &apos;Send Email Report Always&apos;
  inputs:
    subject: &apos;[{environmentStatus}] {passPercentage} tests passed for &quot;Contact API Production&quot; on build $(Build.BuildNumber)&apos;
    toAddress: &apos;$(ReportRecipients)&apos;
    ccAddress: &apos;$(ReportCcRecipients)&apos;
    defaultDomain: mydomain.co.uk
    maxTestFailuresToShow: 1000
    smtpConnectionEndpoint: &apos;SMTP Connection&apos;</code></pre>]]></content:encoded></item><item><title><![CDATA[Clean Up Your Test Names in Postman]]></title><description><![CDATA[<p>Postman tests are a great way to cover integration testing for your API&apos;s, especially when you can have them <a href="https://johnhorner.uk/automating-api-testing-with-postman-newman-and-devops-pipelines">run nightly from a DevOps pipeline</a>. However, when running those tests in Newman, Postman&apos;s CLI tool, tests named things like &quot;Return status 200&quot; don&apos;</p>]]></description><link>https://johnhorner.uk/clean-up-your-test-names-in-postman/</link><guid isPermaLink="false">62a0dee44b66170001ce1133</guid><category><![CDATA[testing]]></category><category><![CDATA[postman]]></category><dc:creator><![CDATA[John Horner]]></dc:creator><pubDate>Wed, 08 Jun 2022 18:12:16 GMT</pubDate><content:encoded><![CDATA[<p>Postman tests are a great way to cover integration testing for your API&apos;s, especially when you can have them <a href="https://johnhorner.uk/automating-api-testing-with-postman-newman-and-devops-pipelines">run nightly from a DevOps pipeline</a>. However, when running those tests in Newman, Postman&apos;s CLI tool, tests named things like &quot;Return status 200&quot; don&apos;t necessarily give you a good clue as to which endpoint was running.</p><p>I wanted to simplify the naming of a large suite of Postman tests as much as possible and the following is the approach I took.</p><p>It is possible, as well as running tests from the request level, to run tests from the collection level, so that they run for all tests. Here&apos;s my collection-level test script:</p><pre><code class="language-javascript">const method = pm.request.url.path.join(&quot;/&quot;).replace(/^api\//, &quot;&quot;);
pm.environment.set(&quot;currentMethod&quot;, method);

pm.test(`${method} - Status code is 200`, () =&gt; {
  pm.response.to.have.status(200);
});

pm.test(`${method} - Response time below 500ms`, () =&gt; {
  pm.expect(pm.response.responseTime).to.be.below(500);
});</code></pre><p>The first line is building the first part of the test title for me - the endpoint that is being tested. For example, if the endpoint is:</p><p><a href="https://someapi.domain.com/api/contacts/v1/getcontact?id=1"><code>https://someapi.domain.com/api/contacts/v1/getcontact?id=1</code></a></p><p>Then the &quot;method&quot; constant will be:</p><p><code>contacts/v1/getcontact</code></p><p>I&apos;m using a regex to remove the api prefix from my test name.</p><p>The next line then injects that into the current environment variables. We&apos;ll need it later.</p><p>Then there&apos;s a couple of tests that I want to run for every endpoint in the collection, the HTTP status code and response time. They use string interpolation to inject the current endpoint in before the rest of the test title.</p><p>All that&apos;s left to do now is retrieve that method title within each individual endpoint tests to use it in the same way:</p><pre><code class="language-javascript">var method = pm.environment.get(&quot;currentMethod&quot;);

var contact = pm.response.json();

pm.test(`${method} - Name valid`, () =&gt; {
    pm.expect(contact).to.have.property(&quot;name&quot;);
});

pm.test(`${method} - ID valid`, () =&gt; {
    pm.expect(contact.id).to.be.greaterThan(0);
});</code></pre><p>And there you have it. Add a similar set of tests for a different endpoint, run this suite and you&apos;d see:</p><pre><code>PASS contacts/v1/getcontact - Status code is 200
PASS contacts/v1/getcontact - Response time below 500ms
PASS contacts/v1/getcontact - Name valid
PASS contacts/v1/getcontact - ID valid
PASS contacts/v1/getaddress - Status code is 200
PASS contacts/v1/getaddress - Response time below 500ms
PASS contacts/v1/getaddress - Name valid
PASS contacts/v1/getaddress - ID valid</code></pre><p>Create multiple folders under the collection for each endpoint, and they&apos;ll all be correctly labelled within the test results, no matter what the endpoint is.</p><p>Happy testing!</p>]]></content:encoded></item></channel></rss>