Skip to content

Commit

Permalink
Merge pull request #99 from empress/test-meta
Browse files Browse the repository at this point in the history
Add tests for metadata and fix anything that is obviously wrong
  • Loading branch information
mansona authored Dec 4, 2020
2 parents 0223564 + 3cc63cf commit 07839af
Show file tree
Hide file tree
Showing 13 changed files with 225 additions and 90 deletions.
20 changes: 13 additions & 7 deletions addon/helpers/excerpt.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ import downsize from 'downsize-cjs';
export function getExcerpt(html, truncateOptions) {
truncateOptions = truncateOptions || {};
// Strip inline and bottom footnotes
var excerpt = html.replace(/<a href="#fn.*?rel="footnote">.*?<\/a>/gi, '');
excerpt = excerpt.replace(/<div class="footnotes"><ol>.*?<\/ol><\/div>/, '');
// Strip other html
excerpt = excerpt.replace(/<\/?[^>]+>/gi, '');
excerpt = excerpt.replace(/(\r\n|\n|\r)+/gm, ' ');
const excerpt = stripHTML(html);

if (!truncateOptions.words && !truncateOptions.characters) {
truncateOptions.words = 50;
Expand All @@ -19,9 +15,19 @@ export function getExcerpt(html, truncateOptions) {
return downsize(excerpt, truncateOptions);
}

export function stripHTML(html) {
let strippedHTML = html.replace(/<a href="#fn.*?rel="footnote">.*?<\/a>/gi, '');
strippedHTML = strippedHTML.replace(/<div class="footnotes"><ol>.*?<\/ol><\/div>/, '');
// Strip other html
strippedHTML = strippedHTML.replace(/<\/?[^>]+>/gi, '');
strippedHTML = strippedHTML.replace(/(\r\n|\n|\r)+/gm, ' ');

return strippedHTML;
}

export function excerpt(content, options/*, hash*/) {
var truncateOptions = options || {};
var excerptText = options.custom_excerpt ? String(options.custom_excerpt) : String(content);
let truncateOptions = options || {};
const excerptText = options.custom_excerpt ? String(options.custom_excerpt) : String(content);

let { words, characters } = truncateOptions;
truncateOptions = { words, characters };
Expand Down
97 changes: 97 additions & 0 deletions addon/services/head-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import HeadData from 'ember-meta/services/head-data';
import { getOwner } from '@ember/application';
import { computed } from '@ember/object';
import config from 'ember-get-config';

import { getExcerpt, stripHTML } from '../helpers/excerpt';

const { blog } = config;

export default class HeadDataService extends HeadData {
get config() {
return config['blog'];
}

@computed('config.title')
get siteName() {
return this.config.title;
}

@computed('routeName')
get currentRouteMeta() {
let currentController = getOwner(this).lookup(`controller:${this.routeName}`)

return currentController.model.post ?? currentController.model;
}

@computed('currentRouteMeta.name', 'routeName')
get title() {
if(this.routeName === 'tag') {
return `Tag: ${this.currentRouteMeta.name}`;
}

if(this.routeName === 'author') {
return `Author: ${this.currentRouteMeta.name}`;
}

return super.title;
}

@computed('currentRouteMeta')
get description() {
let currentModel = this.currentRouteMeta;

if(currentModel && currentModel.html) {
const excerpt = getExcerpt(currentModel.html, {
words: 33
})

return `${excerpt}${excerpt.length !== stripHTML(currentModel.html).length ? '...' : ''}`;
}

return blog.description;
}

@computed('currentRouteMeta.id')
get slug() {
return this.currentRouteMeta?.id;
}

@computed('currentRouteMeta.tags')
get categories() {
return this.currentRouteMeta?.tags?.mapBy('name');
}

@computed('currentRouteMeta.image')
get imgSrc() {
let url = blog.host ? `${blog.host}` : '';

url += this.currentRouteMeta.image || blog.rssLogo || blog.logo;

return url;
}

@computed('router.currentURL')
get url() {
// url is only ever valid if you have a host
if(!blog.host) {
return null;
}

// we remove any trailing / from the host and add it back in to make sure
// that we always have a consistent URL
const normalisedHost = blog.host.replace(/\/$/, '');
const normalisedUrl = this.router.currentURL.replace(/\/$/, '');

return `${normalisedHost}${normalisedUrl}/`;
}

@computed('routeName')
get type() {
if(this.routeName === 'post') {
return 'article';
}

return 'website';
}
}
1 change: 1 addition & 0 deletions app/models/author.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default DS.Model.extend({
coverImage: DS.attr('string'),
coverMeta: DS.attr(),
content: DS.attr('string'),
html: DS.attr(),
website: DS.attr('string'),
twitter: DS.attr('string'),
facebook: DS.attr('string'),
Expand Down
1 change: 1 addition & 0 deletions app/models/tag.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default DS.Model.extend({
image: DS.attr('string'),
imageMeta: DS.attr(),
content: DS.attr('string'),
html: DS.attr(),

// workaround for unstable ember-data relationship id sorting
// see: https://discuss.emberjs.com/t/manual-pagination-in-ember-data-relationships/18087
Expand Down
59 changes: 1 addition & 58 deletions app/services/head-data.js
Original file line number Diff line number Diff line change
@@ -1,58 +1 @@
/* eslint-disable ember/require-computed-macros, ember/require-computed-property-dependencies, ember/no-get, ember/require-return-from-computed */
import HeadData from 'ember-meta/services/head-data';
import { computed, get } from '@ember/object';
import { getOwner } from '@ember/application';
import config from 'ember-get-config';

import { getExcerpt } from '../helpers/excerpt';

const { blog } = config;

export default HeadData.extend({
author: computed('routeName', function() {
return this.get('currentRouteModel.author.name');
}),

currentRouteModel: computed('routeName', function() {
return getOwner(this).lookup(`route:${this.get('routeName')}`).get('currentModel.post') || {};
}),

description: computed('routeName', function() {
let currentModel = this.get('currentRouteModel');

if(currentModel && get(currentModel, 'html')) {
const excerpt = getExcerpt(get(currentModel, 'html'), {
words: 33
})
return `${excerpt}...`;
}

return blog.description;
}),

slug: computed('routeName', function() {
return this.get('currentRouteModel.id');
}),

categories: computed('routeName', function() {
let tags = this.get('currentRouteModel.tags')

if(tags) {
return tags.mapBy('name');
}
}),

imgSrc: computed('routeName', function() {
let url = blog.host ? `${blog.host}` : '';

url += this.currentRouteModel.image || blog.rssLogo || blog.logo;

return url;
}),

url: computed('routeName', function() {
if(!blog.host || !this.slug) { return; }

return `${blog.host}/${this.slug}/`;
})
});
export { default } from 'empress-blog/services/head-data';
22 changes: 1 addition & 21 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,8 @@ const AutomaticNewTag = require('./lib/automatic-new-tag');
module.exports = {
name: require('./package').name,

config(env, config) {
let blog = config.blog || {};

let emberMetaConfig = {
description: blog.description,
imgSrc: blog.rssLogo || blog.logo,
siteName: blog.title,
title: blog.title,
twitterUsername: blog.twitter,

}

if(blog.host) {
if(blog.host.endsWith('/')) {
emberMetaConfig.url = `${blog.host}/`
} else {
emberMetaConfig.url = blog.host;
}
}

config() {
return {
'ember-meta': emberMetaConfig,
blog: {},
fastboot: {
hostWhitelist: [/localhost:\d+/]
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
},
"ember-addon": {
"configPath": "tests/dummy/config",
"after": "ember-meta",
"before": "prember",
"demoURL": "https://empress-blog-casper-template.netlify.com"
}
Expand Down
101 changes: 101 additions & 0 deletions tests/acceptance/meta-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { module, test } from 'qunit';
import { visit } from '@ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';

module('Acceptance | meta test', function(hooks) {
setupApplicationTest(hooks);

test('index meta', async function(assert) {
await visit('/');

assert.dom('head meta[property="og:title"]', document)
.hasAttribute('content', 'empress-blog: The simple JAM stack blog');
assert.dom('head meta[name="description"]', document)
.hasAttribute('content', 'Thoughts, stories and ideas.');
assert.dom('head link[rel="canonical"]', document)
.hasAttribute('href', 'https://empress-blog.netlify.com/');
assert.dom('head meta[property="og:type"]', document)
.hasAttribute('content', 'website');
assert.dom('head meta[property="og:image"]', document)
.hasAttribute('content', 'https://empress-blog.netlify.com/images/logo.png');
assert.dom('head meta[property="og:site_name"]', document)
.hasAttribute('content', 'empress-blog: The simple JAM stack blog');
});

test('content meta', async function(assert) {
await visit('/welcome');

assert.dom('head meta[property="og:title"]', document)
.hasAttribute('content', 'Welcome to empress-blog');
assert.dom('head meta[name="description"]', document)
.hasAttribute('content', `Hey! Welcome to empress-blog, it's great to have you :) We know that first impressions are important, so we've populated your new site with some initial Getting Started posts that will...`);
assert.dom('head meta[name="twitter:label1"]', document)
.hasAttribute('content', 'Written by');
assert.dom('head meta[name="twitter:data1"]', document)
.hasAttribute('content', 'Ghost');
assert.dom('head meta[name="twitter:label2"]', document)
.hasAttribute('content', 'Filed under');
assert.dom('head meta[name="twitter:data2"]', document)
.hasAttribute('content', 'Getting Started, Recent posts');
assert.dom('head link[rel="canonical"]', document)
.hasAttribute('href', 'https://empress-blog.netlify.com/welcome/');
// I'm not testing the value of conent here to avoid timezone variations
assert.dom('head meta[property="article:published_time"]', document)
.hasAttribute('content');
assert.dom('head meta[property="article:tag"]', document)
.hasAttribute('content', 'Getting Started');
assert.dom('head meta[property="og:type"]', document)
.hasAttribute('content', 'article');
assert.dom('head meta[property="og:image"]', document)
.hasAttribute('content', 'https://empress-blog.netlify.com/images/welcome.jpg');
})

test('page meta', async function(assert) {
await visit('/page/chris-manson');

assert.dom('head meta[property="og:title"]', document)
.hasAttribute('content', 'Built with ❤️ by Chris Manson');
assert.dom('head meta[name="description"]', document)
.hasAttribute('content', `Chris Manson is a Ember enthusiast and a member of the Ember Core Learning Team. empress-blog was an experimental project that came out of the work on converting the Ember Guides to...`);
assert.dom('head meta[name="twitter:label1"]', document)
.hasAttribute('content', 'Written by');
assert.dom('head meta[name="twitter:data1"]', document)
.hasAttribute('content', 'Chris Manson');
assert.dom('head link[rel="canonical"]', document)
.hasAttribute('href', 'https://empress-blog.netlify.com/page/chris-manson/');
assert.dom('head meta[property="og:type"]', document)
.hasAttribute('content', 'website');
assert.dom('head meta[property="og:image"]', document)
.hasAttribute('content', 'https://empress-blog.netlify.com/images/built-by.jpg');
});

test('author meta', async function(assert) {
await visit('/author/ghost');

assert.dom('head meta[property="og:title"]', document)
.hasAttribute('content', 'Author: Ghost');
assert.dom('head meta[name="description"]', document)
.hasAttribute('content', 'You can delete this user to remove all the welcome posts');
assert.dom('head link[rel="canonical"]', document)
.hasAttribute('href', 'https://empress-blog.netlify.com/author/ghost/');
assert.dom('head meta[property="og:type"]', document)
.hasAttribute('content', 'website');
assert.dom('head meta[property="og:image"]', document)
.hasAttribute('content', 'https://empress-blog.netlify.com/images/ghost-icon.png');
});

test('tag meta', async function(assert) {
await visit('/tag/getting-started');

assert.dom('head meta[property="og:title"]', document)
.hasAttribute('content', 'Tag: Getting Started');
assert.dom('head meta[name="description"]', document)
.hasAttribute('content', 'A description for the getting-started tag. If you delete this line it will say A collection of X posts where the description should go.');
assert.dom('head link[rel="canonical"]', document)
.hasAttribute('href', 'https://empress-blog.netlify.com/tag/getting-started/');
assert.dom('head meta[property="og:type"]', document)
.hasAttribute('content', 'website');
assert.dom('head meta[property="og:image"]', document)
.hasAttribute('content', 'https://empress-blog.netlify.com/images/logo.png');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,25 @@ module('Acceptance | smoke test', function(hooks) {
test('navigate to all routes', async function(assert) {
await visit('/');
assert.equal(currentURL(), '/');
// test og:title because testem replaces the actual title :(
assert.dom('head meta[property="og:title"]', document).hasAttribute('content', 'empress-blog: The simple JAM stack blog');

await click('.post-card-content-link');
assert.equal(currentURL(), '/welcome');
assert.dom('head meta[property="og:title"]', document).hasAttribute('content', 'Welcome to empress-blog');

await click('.nav .nav-Built a');
assert.equal(currentURL(), '/page/chris-manson');
assert.dom('head meta[property="og:title"]', document).hasAttribute('content', 'Built with ❤️ by Chris Manson');

await click('.nav .nav-Home a');
await click('.static-avatar');
assert.equal(currentURL(), '/author/ghost');
assert.dom('head meta[property="og:title"]', document).hasAttribute('content', 'Author: Ghost');

await click('.post-card-image-link');
await click('.post-full-header a');
assert.equal(currentURL(), '/tag/getting-started');
assert.dom('head meta[property="og:title"]', document).hasAttribute('content', 'Tag: Getting Started');
});
});
3 changes: 2 additions & 1 deletion tests/dummy/config/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ module.exports = function(environment) {
},

blog: {
title: "empress-blog",
title: "empress-blog: The simple JAM stack blog",
description: "Thoughts, stories and ideas.",
coverImage: "/images/blog-cover.jpg",
rssLogo: '/images/logo.png',
navigation: [
{ label: 'Home', route: 'index' },
{ label: 'Built by Chris Manson', route: 'page', id: 'chris-manson' }
Expand Down
2 changes: 1 addition & 1 deletion tests/dummy/page/chris-manson.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ imageMeta:
attributionLink:
featured: true
authors:
- ghost
- chris
date: Tue Jun 12 2018 17:50:55 GMT+0100 (IST)
tags:
---
Expand Down
Binary file added tests/dummy/public/images/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 07839af

Please sign in to comment.