20 Commits

Author SHA1 Message Date
Embrace
2326895768 Restored support to oldest Django versions 2019-02-01 10:16:52 -02:00
Embrace
053afe1bc0 Added the splash screen for iOS and Meta tags to Android and Win8 2019-01-23 12:01:00 -02:00
Embrace
d86732bb9a Readme updated 2018-12-17 07:48:17 -02:00
Silvio Leite
d4d0db5bea Fix tests 2018-11-30 20:39:20 -02:00
Silvio Leite
79c6963219 Included the default serviceworker, updated the manifest, Add the default offline page, updated the unit test, Redme 2018-11-30 20:33:20 -02:00
Silvio Leite
73151d2585 Add coverage on changelog 2018-11-18 09:22:21 -02:00
Silvio Leite
93133a3292 Badges 2018-11-17 11:33:08 -02:00
Silvio Leite
662cf155d7 codecov 2018-11-17 10:11:45 -02:00
Silvio Leite
0d31371002 coverage result 2018-11-17 08:43:16 -02:00
Silvio Leite
43cb44b5c0 Codeclimate config 2018-11-17 08:35:20 -02:00
Silvio Leite
c7e9813ac5 prefix path coverage 2018-11-16 17:23:25 -02:00
Silvio Leite
ed2caecbd7 prefix path coverage 2018-11-16 17:11:52 -02:00
Silvio Leite
cd144e2ef7 prefix path coverage 2018-11-16 17:07:58 -02:00
Silvio Leite
625eee756c fix travis 2018-11-16 16:39:41 -02:00
Silvio Leite
eba9fe5951 fix travis 2018-11-16 16:25:26 -02:00
Silvio Leite
7c0df3201e Fix travis.yml 2018-11-16 16:12:22 -02:00
Silvio Leite
fc56890d83 Fix travis.yml 2018-11-16 16:08:27 -02:00
Silvio Leite
45d344503f Fix travis.yml 2018-11-16 16:04:14 -02:00
Silvio Leite
86ed4b6504 Fix travis.yml 2018-11-16 15:47:21 -02:00
Silvio Leite
e45b83d54c Test coverage on codeclimate 2018-11-16 14:44:31 -02:00
39 changed files with 406 additions and 35 deletions

2
.coveragerc Normal file
View File

@@ -0,0 +1,2 @@
[run]
source=pwa

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@ build/
dist/ dist/
*.egg-info/ *.egg-info/
.tox/ .tox/
.coverage

View File

@@ -7,4 +7,9 @@ install:
- pip install Django==$DJANGO_VERSION - pip install Django==$DJANGO_VERSION
- pip install tox-travis - pip install tox-travis
- pip install -q -r requirements-dev.txt - pip install -q -r requirements-dev.txt
script: tox - pip install coverage
- pip install codecov
script:
- coverage run runtests.py
after_success:
- codecov

View File

@@ -6,7 +6,40 @@
## 1.0.0 ## 1.0.0
### Added
- Unit tests - Unit tests
- Add Oritentation on manifest.json - Option `Oritentation` on manifest.json
- Add tox - tox.ini
- Coverage
## 1.0.1
### Added
- Add django 2 requirement
- Use templateviews instead of own implementations
- Add content_types
- Update `README.md`
- Add `PWA_APP_FETCH_URL`
- Add default_config in `__init__.py`
- Add basic serviceworker
- Add default offline page and default icons
### Changed
- Updated the unit tests
## 1.0.2
### Fixed
- Fix tox.ini to install pypandoc
### Added
- The support to splash screen for iOS Meta tags `apple-touch-startup-image`
- Meta tag `mobile-web-app-capable`
- Meta tag `application-name`
- Meta tag `msapplication-TileColor` and `msapplication-TileImage` for win8
- Meta tag `rel="icon"` with default icon
- Images for splash screen
- Include the new images to `serviceworker.js`
### Changed
- Update `CHANGELOG.md`
- Update `README.md`

View File

@@ -1,2 +1,3 @@
include *.md include *.md
recursive-include pwa/templates * recursive-include pwa/templates *
recursive-include pwa/static *

View File

@@ -1,5 +1,12 @@
django-pwa django-pwa
===== =====
[![Build Status](https://travis-ci.org/silviolleite/django-pwa.svg)](https://travis-ci.org/silviolleite/django-pwa)
[![Maintainability](https://api.codeclimate.com/v1/badges/246542ea921058c4f76f/maintainability)](https://codeclimate.com/github/silviolleite/django-pwa/maintainability)
[![codecov](https://codecov.io/gh/silviolleite/django-pwa/branch/master/graph/badge.svg)](https://codecov.io/gh/silviolleite/django-pwa)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/django-pwa.svg)](https://pypi.org/project/django-pwa/)
[![PyPI - Downloads](https://img.shields.io/pypi/v/django-pwa.svg)](https://pypi.org/project/django-pwa)
[![PyPI - Downloads](https://img.shields.io/pypi/djversions/django-pwa.svg)](https://pypi.org/project/django-pwa)
This Django app turns your project into a [progressive web app](https://developers.google.com/web/progressive-web-apps/). Navigating to your site on an Android phone will prompt you to add the app to your home screen. This Django app turns your project into a [progressive web app](https://developers.google.com/web/progressive-web-apps/). Navigating to your site on an Android phone will prompt you to add the app to your home screen.
![Prompt for install](https://github.com/silviolleite/django-pwa/raw/master/images/screenshot1.png) ![Prompt for install](https://github.com/silviolleite/django-pwa/raw/master/images/screenshot1.png)
@@ -30,8 +37,9 @@ INSTALLED_APPS = [
] ]
``` ```
Configure your app name, description, and icons in settings.py: Configure your app name, description, icons and splash screen images in settings.py:
```python ```python
PWA_APP_NAME = 'My App' PWA_APP_NAME = 'My App'
PWA_APP_DESCRIPTION = "My app description" PWA_APP_DESCRIPTION = "My app description"
PWA_APP_THEME_COLOR = '#0A0302' PWA_APP_THEME_COLOR = '#0A0302'
@@ -45,16 +53,22 @@ PWA_APP_ICONS = [
'sizes': '160x160' 'sizes': '160x160'
} }
] ]
PWA_APP_SPLASH_SCREEN = [
{
'src': '/static/images/icons/splash-640x1136.png',
'media': '(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)'
}
]
PWA_APP_DIR = 'ltr' PWA_APP_DIR = 'ltr'
PWA_APP_LANG = 'en-US' PWA_APP_LANG = 'en-US'
``` ```
All settings are optional, and the app will work fine with its internal defaults. Highly recommend setting at least `PWA_APP_NAME` and `PWA_APP_DESCRIPTION`. All settings are optional, and the app will work fine with its internal defaults. Highly recommend setting at least `PWA_APP_NAME`, `PWA_APP_DESCRIPTION`, `PWA_APP_ICONS` and `PWA_APP_SPLASH_SCREEN`.
Add the progressive web app URLs to urls.py: Add the progressive web app URLs to urls.py:
```python ```python
from django.conf.urls import url, include from django.urls import url, include
urlpatterns = [ urlpatterns = [
... ...
@@ -80,18 +94,95 @@ While running the Django test server:
1. Verify that `/manifest.json` is being served 1. Verify that `/manifest.json` is being served
1. Verify that `/serviceworker.js` is being served 1. Verify that `/serviceworker.js` is being served
1. Verify that `/offline` is being served
1. Use the Application tab in the Chrome Developer Tools to verify the progressive web app is configured correctly. 1. Use the Application tab in the Chrome Developer Tools to verify the progressive web app is configured correctly.
1. Use the "Add to homescreen" link on the Application Tab to verify you can add the app successfully. 1. Use the "Add to homescreen" link on the Application Tab to verify you can add the app successfully.
The Service Worker
=====
By default, the service worker implemented by this app is:
```js
// Base Service Worker implementation. To use your own Service Worker, set the PWA_SERVICE_WORKER_PATH variable in settings.py
var staticCacheName = "django-pwa-v" + new Date().getTime();
var filesToCache = [
'/offline',
'/css/django-pwa-app.css',
'/images/icons/icon-72x72.png',
'/images/icons/icon-96x96.png',
'/images/icons/icon-128x128.png',
'/images/icons/icon-144x144.png',
'/images/icons/icon-152x152.png',
'/images/icons/icon-192x192.png',
'/images/icons/icon-384x384.png',
'/images/icons/icon-512x512.png',
'/static/images/icons/splash-640x1136.png',
'/static/images/icons/splash-750x1334.png',
'/static/images/icons/splash-1242x2208.png',
'/static/images/icons/splash-1125x2436.png',
'/static/images/icons/splash-828x1792.png',
'/static/images/icons/splash-1242x2688.png',
'/static/images/icons/splash-1536x2048.png',
'/static/images/icons/splash-1668x2224.png',
'/static/images/icons/splash-1668x2388.png',
'/static/images/icons/splash-2048x2732.png'
];
// Cache on install
self.addEventListener("install", event => {
this.skipWaiting();
event.waitUntil(
caches.open(staticCacheName)
.then(cache => {
return cache.addAll(filesToCache);
})
)
});
// Clear cache on activate
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames
.filter(cacheName => (cacheName.startsWith("django-pwa-")))
.filter(cacheName => (cacheName !== staticCacheName))
.map(cacheName => caches.delete(cacheName))
);
})
);
});
// Serve from Cache
self.addEventListener("fetch", event => {
event.respondWith(
caches.match(event.request)
.then(response => {
return response || fetch(event.request);
})
.catch(() => {
return caches.match('offline');
})
)
});
```
Adding Your Own Service Worker Adding Your Own Service Worker
===== =====
By default, the service worker implemented by this app is empty. To add service worker functionality, you'll want to create a `serviceworker.js` or similarly named file, and then point at it using the PWA_SERVICE_WORKER_PATH variable. To add service worker functionality, you'll want to create a `serviceworker.js` or similarly named template in a template directory, and then point at it using the PWA_SERVICE_WORKER_PATH variable (PWA_APP_FETCH_URL is passed through).
```python ```python
PWA_SERVICE_WORKER_PATH = os.path.join(BASE_DIR, 'my_app', 'serviceworker.js') PWA_SERVICE_WORKER_PATH = os.path.join(BASE_DIR, 'my_app', 'serviceworker.js')
``` ```
The offline view
=====
By default, the offline view is implemented in `templates/offline.html`
You can overwrite it in a template directory if you continue using the default `serviceworker.js`.
Feedback Feedback
===== =====
I welcome your feedback and pull requests. Enjoy! I welcome your feedback and pull requests. Enjoy!

View File

@@ -0,0 +1 @@
default_app_config = 'pwa.apps.PwaConfig'

View File

@@ -1,11 +1,11 @@
""" Settings required by django-progressive-web-app. """ """ Settings required by django-app. """
from django.conf import settings from django.conf import settings
import os import os
# Path to the service worker implementation. Default implementation is empty. # Path to the service worker implementation. Default implementation is empty.
PWA_SERVICE_WORKER_PATH = getattr(settings, 'PWA_SERVICE_WORKER_PATH', PWA_SERVICE_WORKER_PATH = getattr(settings, 'PWA_SERVICE_WORKER_PATH',
os.path.join(os.path.abspath(os.path.dirname(__file__)), 'templates', 'serviceworker.js')) os.path.join(os.path.abspath(os.path.dirname(__file__)), 'templates',
'serviceworker.js'))
# App parameters to include in manifest.json and appropriate meta tags # App parameters to include in manifest.json and appropriate meta tags
PWA_APP_NAME = getattr(settings, 'PWA_APP_NAME', 'MyApp') PWA_APP_NAME = getattr(settings, 'PWA_APP_NAME', 'MyApp')
PWA_APP_DESCRIPTION = getattr(settings, 'PWA_APP_DESCRIPTION', 'My Progressive Web App') PWA_APP_DESCRIPTION = getattr(settings, 'PWA_APP_DESCRIPTION', 'My Progressive Web App')
@@ -15,12 +15,84 @@ PWA_APP_BACKGROUND_COLOR = getattr(settings, 'PWA_APP_BACKGROUND_COLOR', '#fff')
PWA_APP_DISPLAY = getattr(settings, 'PWA_APP_DISPLAY', 'standalone') PWA_APP_DISPLAY = getattr(settings, 'PWA_APP_DISPLAY', 'standalone')
PWA_APP_ORIENTATION = getattr(settings, 'PWA_APP_ORIENTATION', 'any') PWA_APP_ORIENTATION = getattr(settings, 'PWA_APP_ORIENTATION', 'any')
PWA_APP_START_URL = getattr(settings, 'PWA_APP_START_URL', '/') PWA_APP_START_URL = getattr(settings, 'PWA_APP_START_URL', '/')
PWA_APP_FETCH_URL = getattr(settings, 'PWA_APP_FETCH_URL', '/')
PWA_APP_ICONS = getattr(settings, 'PWA_APP_ICONS', [ PWA_APP_ICONS = getattr(settings, 'PWA_APP_ICONS', [
{ {
'src': '/', 'src': '/static/images/icons/icon-72x72.png',
'sizes': '160x160' 'size': '72x72'
},
{
'src': '/static/images/icons/icon-96x96.png',
'size': '96x96'
},
{
'src': '/static/images/icons/icon-128x128.png',
'size': '128x128'
},
{
'src': '/static/images/icons/icon-144x144.png',
'size': '144x144'
},
{
'src': '/static/images/icons/icon-152x152.png',
'size': '152x152'
},
{
'src': '/static/images/icons/icon-192x192.png',
'size': '192x192'
},
{
'src': '/static/images/icons/icon-384x384.png',
'size': '384x384'
},
{
'src': '/static/images/icons/icon-512x512.png',
'size': '512x512'
} }
]) ])
PWA_APP_SPLASH_SCREEN = getattr(settings, 'PWA_APP_SPLASH_SCREEN', [
{
'src': '/static/images/icons/splash-640x1136.png',
'media': '(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)'
},
{
'src': '/static/images/icons/splash-750x1334.png',
'media': '(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)'
},
{
'src': '/static/images/icons/splash-1242x2208.png',
'media': '(device-width: 621px) and (device-height: 1104px) and (-webkit-device-pixel-ratio: 3)'
},
{
'src': '/static/images/icons/splash-1125x2436.png',
'media': '(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3)'
},
{
'src': '/static/images/icons/splash-828x1792.png',
'media': '(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2)'
},
{
'src': '/static/images/icons/splash-1242x2688.png',
'media': '(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3)'
},
{
'src': '/static/images/icons/splash-1536x2048.png',
'media': '(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2)'
},
{
'src': '/static/images/icons/splash-1668x2224.png',
'media': '(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2)'
},
{
'src': '/static/images/icons/splash-1668x2388.png',
'media': '(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2)'
},
{
'src': '/static/images/icons/splash-2048x2732.png',
'media': '(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2)'
}
])
PWA_APP_DIR = getattr(settings, 'PWA_APP_DIR', 'auto') PWA_APP_DIR = getattr(settings, 'PWA_APP_DIR', 'auto')
PWA_APP_LANG = getattr(settings, 'PWA_APP_LANG', 'en-US') PWA_APP_LANG = getattr(settings, 'PWA_APP_LANG', 'en-US')

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -0,0 +1,11 @@
{% load static %}<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Default offline template</title>
<link href="{% static '/css/django-pwa-app.css' %}" rel="stylesheet">
</head>
<body>
<h1>You are currently not connected to any networks.</h1>
</body>
</html>

View File

@@ -1,27 +1,48 @@
<!-- Path to manifest.json --> <!-- Path to manifest.json -->
<link rel="manifest" href="/manifest.json"> <link rel="manifest" href="/manifest.json">
<!-- Icons for Apple Devices --> <!-- Add to homescreen for Chrome on Android -->
{% for icon in PWA_APP_ICONS %} <meta name="mobile-web-app-capable" content="yes">
<link rel="apple-touch-icon" href="{{ icon.src }}" sizes="{{ icon.sizes }}"> <meta name="application-name" content="{{ PWA_APP_NAME }}">
{% endfor %}
<!-- Chrome for Android theme color -->
<meta name="theme-color" content="{{ PWA_APP_THEME_COLOR }}"> <meta name="theme-color" content="{{ PWA_APP_THEME_COLOR }}">
<!-- Add to homescreen for Safari on iOS -->
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-title" content="{{ PWA_APP_NAME }}"> <meta name="apple-mobile-web-app-title" content="{{ PWA_APP_NAME }}">
<meta name="apple-mobile-web-app-status-bar-style" content="default"> <meta name="apple-mobile-web-app-status-bar-style" content="default">
{% for icon in PWA_APP_ICONS %}
<link rel="apple-touch-icon" href="{{ icon.src }}" sizes="{{ icon.size }}">
{% endfor %}
{% for splash in PWA_APP_SPLASH_SCREEN%}
<link href="{{ splash.src }}" media="{{ splash.media }}" rel="apple-touch-startup-image"/>
{% endfor %}
<!-- Tile for Win8 -->
<meta name="msapplication-TileColor" content="{{ PWA_APP_BACKGROUND_COLOR }}">
{% with PWA_APP_ICONS|last as icon %}
<meta name="msapplication-TileImage" content="{{ icon.src }}">
<link rel="icon" sizes="{{ icon.size }}" href="{{ icon.src }}">
{% endwith %}
<script type="text/javascript"> <script type="text/javascript">
// Initialize the service worker // Initialize the service worker
if ('serviceWorker' in navigator) { if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/serviceworker.js', { navigator.serviceWorker.register('/serviceworker.js', {
scope: '.' // <--- THIS BIT IS REQUIRED scope: '.'
}).then(function (registration) { }).then(function (registration) {
// Registration was successful // Registration was successful
console.log('django-progressive-web-app: ServiceWorker registration successful with scope: ', registration.scope); console.log('django-pwa: ServiceWorker registration successful with scope: ', registration.scope);
}, function (err) { }, function (err) {
// registration failed :( // registration failed :(
console.log('django-progressive-web-app: ServiceWorker registration failed: ', err); console.log('django-pwa: ServiceWorker registration failed: ', err);
}); });
} }
</script> </script>

View File

@@ -1,2 +1,63 @@
// Empty Service Worker implementation. To use your own Service Worker, set the PWA_SERVICE_WORKER_PATH variable in // Base Service Worker implementation. To use your own Service Worker, set the PWA_SERVICE_WORKER_PATH variable in settings.py
// settings.py
var staticCacheName = "django-pwa-v" + new Date().getTime();
var filesToCache = [
'/offline',
'/static/css/django-pwa-app.css',
'/static/images/icons/icon-72x72.png',
'/static/images/icons/icon-96x96.png',
'/static/images/icons/icon-128x128.png',
'/static/images/icons/icon-144x144.png',
'/static/images/icons/icon-152x152.png',
'/static/images/icons/icon-192x192.png',
'/static/images/icons/icon-384x384.png',
'/static/images/icons/icon-512x512.png',
'/static/images/icons/splash-640x1136.png',
'/static/images/icons/splash-750x1334.png',
'/static/images/icons/splash-1242x2208.png',
'/static/images/icons/splash-1125x2436.png',
'/static/images/icons/splash-828x1792.png',
'/static/images/icons/splash-1242x2688.png',
'/static/images/icons/splash-1536x2048.png',
'/static/images/icons/splash-1668x2224.png',
'/static/images/icons/splash-1668x2388.png',
'/static/images/icons/splash-2048x2732.png'
];
// Cache on install
self.addEventListener("install", event => {
this.skipWaiting();
event.waitUntil(
caches.open(staticCacheName)
.then(cache => {
return cache.addAll(filesToCache);
})
)
});
// Clear cache on activate
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames
.filter(cacheName => (cacheName.startsWith("django-pwa-")))
.filter(cacheName => (cacheName !== staticCacheName))
.map(cacheName => caches.delete(cacheName))
);
})
);
});
// Serve from Cache
self.addEventListener("fetch", event => {
event.respondWith(
caches.match(event.request)
.then(response => {
return response || fetch(event.request);
})
.catch(() => {
return caches.match('offline');
})
)
});

View File

@@ -1,8 +1,10 @@
from django.conf.urls import url from django.conf.urls import url
from .views import manifest, service_worker
from .views import manifest, service_worker, offline
# Serve up serviceworker.js and manifest.json at the root # Serve up serviceworker.js and manifest.json at the root
urlpatterns = [ urlpatterns = [
url('^serviceworker.js$', service_worker, name="serviceworker"), url('^serviceworker.js$', service_worker, name='serviceworker'),
url('^manifest.json$', manifest, name="manifest") url('^manifest.json$', manifest, name='manifest'),
url('^offline/$', offline, name='offline')
] ]

View File

@@ -15,3 +15,7 @@ def manifest(request):
for setting_name in dir(app_settings) for setting_name in dir(app_settings)
if setting_name.startswith('PWA_') if setting_name.startswith('PWA_')
}) })
def offline(request):
return render(request, "offline.html")

View File

@@ -10,16 +10,21 @@ try:
import pypandoc import pypandoc
long_description = pypandoc.convert('README.md', 'rst') long_description = pypandoc.convert('README.md', 'rst')
except: except RuntimeError:
long_description = short_description long_description = short_description
# allow setup.py to be run from any path # allow setup.py to be run from any path
os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))
install_requirements = [
"django>=1.8",
]
setup( setup(
name='django-pwa', name='django-pwa',
version='1.0.0', version='1.0.3',
packages=find_packages(), packages=find_packages(),
install_requires=install_requirements,
include_package_data=True, include_package_data=True,
license='MIT License', license='MIT License',
description=short_description, description=short_description,
@@ -30,7 +35,12 @@ setup(
classifiers=[ classifiers=[
'Environment :: Web Environment', 'Environment :: Web Environment',
'Framework :: Django', 'Framework :: Django',
'Framework :: Django :: 1.8',
'Framework :: Django :: 1.9',
'Framework :: Django :: 1.10', 'Framework :: Django :: 1.10',
'Framework :: Django :: 1.11',
'Framework :: Django :: 2.0',
'Framework :: Django :: 2.1',
'Intended Audience :: Developers', 'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License', 'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent', 'Operating System :: OS Independent',

View File

@@ -33,4 +33,6 @@ DATABASES = {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'mydatabase', 'NAME': 'mydatabase',
} }
} }
STATIC_URL = '/static/'

View File

@@ -15,6 +15,7 @@ class AppSettingsTest(TestCase):
'PWA_APP_DISPLAY', 'PWA_APP_DISPLAY',
'PWA_APP_ORIENTATION', 'PWA_APP_ORIENTATION',
'PWA_APP_START_URL', 'PWA_APP_START_URL',
'PWA_APP_FETCH_URL',
'PWA_APP_ICONS', 'PWA_APP_ICONS',
'PWA_APP_DIR', 'PWA_APP_DIR',
'PWA_APP_LANG' 'PWA_APP_LANG'

View File

@@ -14,12 +14,34 @@ class CreateMetaTemplateTagTest(TestCase):
def test_has_tags(self): def test_has_tags(self):
"""Must contains the tags in HTML""" """Must contains the tags in HTML"""
tags = [ tags = [
'<link rel="apple-touch-icon" href="/" sizes="160x160">', '<link rel="apple-touch-icon" href="/static/images/icons/icon-72x72.png" sizes="72x72">',
'<link rel="apple-touch-icon" href="/static/images/icons/icon-96x96.png" sizes="96x96">',
'<link rel="apple-touch-icon" href="/static/images/icons/icon-128x128.png" sizes="128x128">',
'<link rel="apple-touch-icon" href="/static/images/icons/icon-144x144.png" sizes="144x144">',
'<link rel="apple-touch-icon" href="/static/images/icons/icon-152x152.png" sizes="152x152">',
'<link rel="apple-touch-icon" href="/static/images/icons/icon-192x192.png" sizes="192x192">',
'<link rel="apple-touch-icon" href="/static/images/icons/icon-384x384.png" sizes="384x384">',
'<link rel="apple-touch-icon" href="/static/images/icons/icon-512x512.png" sizes="512x512">',
'<link rel="manifest" href="/manifest.json">', '<link rel="manifest" href="/manifest.json">',
'<meta name="mobile-web-app-capable" content="yes">',
'<meta name="theme-color" content="#000">', '<meta name="theme-color" content="#000">',
'<meta name="apple-mobile-web-app-capable" content="yes">', '<meta name="apple-mobile-web-app-capable" content="yes">',
'<meta name="apple-mobile-web-app-title" content="MyApp">', '<meta name="apple-mobile-web-app-title" content="MyApp">',
'<meta name="apple-mobile-web-app-status-bar-style" content="default">' '<meta name="application-name" content="MyApp">',
'<meta name="apple-mobile-web-app-status-bar-style" content="default">',
'<link rel="icon" sizes="512x512" href="/static/images/icons/icon-512x512.png">',
'<link href="/static/images/icons/splash-640x1136.png" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image"/>',
'<link href="/static/images/icons/splash-750x1334.png" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image"/>',
'<link href="/static/images/icons/splash-1242x2208.png" media="(device-width: 621px) and (device-height: 1104px) and (-webkit-device-pixel-ratio: 3)" rel="apple-touch-startup-image"/>',
'<link href="/static/images/icons/splash-1125x2436.png" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3)" rel="apple-touch-startup-image"/>',
'<link href="/static/images/icons/splash-828x1792.png" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image"/>',
'<link href="/static/images/icons/splash-1242x2688.png" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3)" rel="apple-touch-startup-image"/>',
'<link href="/static/images/icons/splash-1536x2048.png" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image"/>',
'<link href="/static/images/icons/splash-1668x2224.png" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image"/>',
'<link href="/static/images/icons/splash-1668x2388.png" media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image"/>',
'<link href="/static/images/icons/splash-2048x2732.png" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image"/>',
'<meta name="msapplication-TileColor" content="#fff">',
'<meta name="msapplication-TileImage" content="/static/images/icons/icon-512x512.png">'
] ]
for text in tags: for text in tags:
with self.subTest(): with self.subTest():
@@ -33,9 +55,9 @@ class CreateMetaTemplateTagTest(TestCase):
"navigator.serviceWorker.register('/serviceworker.js', {", "navigator.serviceWorker.register('/serviceworker.js', {",
"scope: '.'", "scope: '.'",
"}).then(function (registration) {", "}).then(function (registration) {",
"console.log('django-progressive-web-app: ServiceWorker registration successful with scope: ', registration.scope);", "console.log('django-pwa: ServiceWorker registration successful with scope: ', registration.scope);",
"}, function (err) {", "}, function (err) {",
"console.log('django-progressive-web-app: ServiceWorker registration failed: ', err);", "console.log('django-pwa: ServiceWorker registration failed: ', err);",
"});", "});",
"</script>" "</script>"
] ]

View File

@@ -41,3 +41,13 @@ class ManifestTest(TestCase):
for expected in contents: for expected in contents:
with self.subTest(): with self.subTest():
self.assertContains(self.response, expected) self.assertContains(self.response, expected)
class OfflineTest(TestCase):
def setUp(self):
self.response = self.client.get(r('offline'))
def test_get(self):
"""GET /offline Should return status code 200"""
self.assertEqual(200, self.response.status_code)

22
tox.ini
View File

@@ -1,10 +1,26 @@
[tox] [tox]
envlist = py36-django{20} envlist =
py35-django{18,19,110,111,20,21}
py36-django{20}
py36-django{21}
py37-django{20}
py37-django{21}
[testenv] [testenv]
commands = python runtests.py commands = python runtests.py
setenv = setenv =
DJANGO_SETTINGS_MODULE=tests.settings DJANGO_SETTINGS_MODULE=tests.settings
PYTHONPATH={toxinidir} PYTHONPATH={toxinidir}
basepython = py36: python3.6 basepython =
deps = django20: Django==2.0 py35: python3.5
py36: python3.6
py37: python3.7
deps =
django18: django==1.8
django19: django==1.9
django110: django==1.10
django111: django==1.11
django20: Django==2.0
django21: Django==2.1
pypandoc==1.3.3