addons-server/mkt/submit/tests/test_views.py

1021 строка
40 KiB
Python
Исходник Обычный вид История

# -*- coding: utf-8 -*-
import json
import os
from django.conf import settings
import mock
from nose.tools import eq_
from pyquery import PyQuery as pq
import waffle
import amo
from amo.helpers import urlparams
import amo.tests
from amo.tests import formset, initial
from amo.tests.test_helpers import get_image_path
from amo.urlresolvers import reverse
from addons.models import (Addon, AddonCategory, AddonDeviceType, AddonUser,
Category, DeviceType)
from addons.utils import ReverseNameLookup
from apps.users.models import UserNotification
from apps.users.notifications import app_surveys
from files.tests.test_models import UploadTest as BaseUploadTest
from market.models import Price
import mkt
2012-02-21 13:13:03 +04:00
from mkt.submit.models import AppSubmissionChecklist
import paypal
from translations.models import Translation
from users.models import UserProfile
from mkt.webapps.models import Webapp
class TestSubmit(amo.tests.TestCase):
fixtures = ['base/users']
def setUp(self):
self.user = self.get_user()
assert self.client.login(username=self.user.email, password='password')
def get_user(self):
return UserProfile.objects.get(username='regularuser')
def _test_anonymous(self):
self.client.logout()
r = self.client.get(self.url, follow=True)
self.assertLoginRedirects(r, self.url)
def _test_progress_display(self, completed, current):
"""Test that the correct steps are highlighted."""
r = self.client.get(self.url)
progress = pq(r.content)('#submission-progress')
# Check the completed steps.
completed_found = progress.find('.completed')
for idx, step in enumerate(completed):
li = completed_found.eq(idx)
eq_(li.text(), unicode(mkt.APP_STEPS_TITLE[step]))
# Check that we link back to the Developer Agreement.
terms_link = progress.find('.terms a')
if 'terms' in completed:
eq_(terms_link.attr('href'),
reverse('mkt.developers.docs', args=['policies', 'agreement']))
else:
eq_(terms_link.length, 0)
# Check the current step.
eq_(progress.find('.current').text(),
unicode(mkt.APP_STEPS_TITLE[current]))
class TestTerms(TestSubmit):
fixtures = ['base/users']
def setUp(self):
super(TestTerms, self).setUp()
self.user.update(read_dev_agreement=False)
self.url = reverse('submit.app.terms')
def test_anonymous(self):
self.client.logout()
r = self.client.get(self.url, follow=True)
self.assertLoginRedirects(r, self.url)
def test_jump_to_step(self):
r = self.client.get(reverse('submit.app'), follow=True)
self.assertRedirects(r, self.url)
def test_page(self):
r = self.client.get(self.url)
eq_(r.status_code, 200)
doc = pq(r.content)('#submit-terms')
eq_(doc.length, 1)
eq_(doc.find('input[name=newsletter]').siblings('label').length, 1,
'Missing its <label>!')
def test_progress_display(self):
self._test_progress_display([], 'terms')
def test_agree(self):
r = self.client.post(self.url, {'read_dev_agreement': True})
self.assertRedirects(r, reverse('submit.app.manifest'))
#dt = self.get_user().read_dev_agreement
#assert close_to_now(dt), (
# 'Expected date of agreement read to be close to now. Was %s' % dt)
eq_(self.get_user().read_dev_agreement, True)
eq_(UserNotification.objects.count(), 0)
def test_agree_and_sign_me_up(self):
r = self.client.post(self.url, {'read_dev_agreement': True,
'newsletter': True})
self.assertRedirects(r, reverse('submit.app.manifest'))
#dt = self.get_user().read_dev_agreement
#assert close_to_now(dt), (
# 'Expected date of agreement read to be close to now. Was %s' % dt)
eq_(self.get_user().read_dev_agreement, True)
eq_(UserNotification.objects.count(), 1)
notes = UserNotification.objects.filter(user=self.user, enabled=True,
notification_id=app_surveys.id)
eq_(notes.count(), 1, 'Expected to not be subscribed to newsletter')
def test_disagree(self):
r = self.client.post(self.url)
eq_(r.status_code, 200)
eq_(self.user.read_dev_agreement, False)
eq_(UserNotification.objects.count(), 0)
class TestManifest(TestSubmit):
fixtures = ['base/users']
def setUp(self):
super(TestManifest, self).setUp()
self.user.update(read_dev_agreement=False)
self.url = reverse('submit.app.manifest')
def _step(self):
#self.user.update(read_dev_agreement=datetime.datetime.now())
self.user.update(read_dev_agreement=True)
def test_anonymous(self):
self._test_anonymous()
def test_cannot_skip_prior_step(self):
r = self.client.get(self.url, follow=True)
# And we start back at one...
self.assertRedirects(r, reverse('submit.app.terms'))
def test_jump_to_step(self):
# I already read the Terms.
self._step()
# So jump me to the Manifest step.
r = self.client.get(reverse('submit.app'), follow=True)
self.assertRedirects(r, reverse('submit.app.manifest'))
def test_page(self):
self._step()
r = self.client.get(self.url)
eq_(r.status_code, 200)
eq_(pq(r.content)('#submit-manifest').length, 1)
def test_progress_display(self):
self._step()
self._test_progress_display(['terms'], 'manifest')
class UploadAddon(object):
def post(self, desktop_platforms=[amo.PLATFORM_ALL], mobile_platforms=[],
expect_errors=False):
d = dict(upload=self.upload.pk,
desktop_platforms=[p.id for p in desktop_platforms],
mobile_platforms=[p.id for p in mobile_platforms])
r = self.client.post(self.url, d, follow=True)
eq_(r.status_code, 200)
if not expect_errors:
# Show any unexpected form errors.
if r.context and 'form' in r.context:
eq_(r.context['form'].errors, {})
return r
class BaseWebAppTest(BaseUploadTest, UploadAddon, amo.tests.TestCase):
fixtures = ['base/apps', 'base/users', 'base/platforms']
def setUp(self):
super(BaseWebAppTest, self).setUp()
self.manifest = os.path.join(settings.ROOT, 'mkt', 'submit', 'tests',
'webapps', 'mozball.webapp')
self.manifest_url = 'http://allizom.org/mozball.webapp'
self.upload = self.get_upload(abspath=self.manifest)
self.upload.name = self.manifest_url
self.upload.save()
self.url = reverse('submit.app.manifest')
assert self.client.login(username='regular@mozilla.com',
password='password')
# Complete first step.
self.client.post(reverse('submit.app.terms'),
{'read_dev_agreement': True})
def post_addon(self):
2012-02-21 03:43:51 +04:00
eq_(Addon.objects.count(), 0)
self.post()
2012-02-21 03:43:51 +04:00
return Addon.objects.get()
class TestCreateWebApp(BaseWebAppTest):
def test_post_app_redirect(self):
r = self.post()
webapp = Webapp.objects.get()
self.assertRedirects(r,
reverse('submit.app.details', args=[webapp.app_slug]))
def test_no_hint(self):
self.post_addon()
self.upload = self.get_upload(abspath=self.manifest)
r = self.client.post(reverse('mkt.developers.upload_manifest'),
dict(manifest=self.manifest_url), follow=True)
eq_(r.status_code, 200)
assert 'already submitted' not in r.content, (
'Unexpected helpful error (trap_duplicate)')
assert 'already exists' not in r.content, (
'Unexpected validation error (verify_app_domain)')
def test_hint_for_same_manifest(self):
waffle.models.Switch.objects.create(name='webapps-unique-by-domain',
active=True)
self.post_addon()
self.upload = self.get_upload(abspath=self.manifest)
r = self.client.post(reverse('mkt.developers.upload_manifest'),
dict(manifest=self.manifest_url))
data = json.loads(r.content)
assert 'Oops' in data['validation']['messages'][0]['message'], (
'Expected oops')
def test_no_hint_for_same_manifest_different_author(self):
waffle.models.Switch.objects.create(name='webapps-unique-by-domain',
active=True)
self.post_addon()
# Submit same manifest as different user.
assert self.client.login(username='clouserw@gmail.com',
password='password')
self.upload = self.get_upload(abspath=self.manifest)
r = self.client.post(reverse('mkt.developers.upload_manifest'),
dict(manifest=self.manifest_url))
data = json.loads(r.content)
eq_(data['validation']['messages'][0]['message'],
'An app already exists on this domain; only one app per domain is '
'allowed.')
2012-02-21 03:43:51 +04:00
def test_app_from_uploaded_manifest(self):
addon = self.post_addon()
eq_(addon.type, amo.ADDON_WEBAPP)
eq_(addon.guid, None)
eq_(unicode(addon.name), u'MozillaBall ょ')
eq_(addon.slug, 'app-%s' % addon.id)
eq_(addon.app_slug, u'mozillaball-ょ')
eq_(addon.summary, u'Exciting Open Web development action!')
eq_(Translation.objects.get(id=addon.summary.id, locale='it'),
u'Azione aperta emozionante di sviluppo di fotoricettore!')
def test_manifest_with_any_extension(self):
self.manifest = os.path.join(settings.ROOT, 'mkt', 'developers',
'tests', 'addons', 'mozball.owa')
self.upload = self.get_upload(abspath=self.manifest, is_webapp=True)
addon = self.post_addon()
eq_(addon.type, amo.ADDON_WEBAPP)
def test_version_from_uploaded_manifest(self):
addon = self.post_addon()
eq_(addon.current_version.version, '1.0')
def test_file_from_uploaded_manifest(self):
addon = self.post_addon()
files = addon.current_version.files.all()
eq_(len(files), 1)
eq_(files[0].status, amo.STATUS_PUBLIC)
class TestCreateWebAppFromManifest(BaseWebAppTest):
def setUp(self):
super(TestCreateWebAppFromManifest, self).setUp()
Webapp.objects.create(app_slug='xxx',
app_domain='http://existing-app.com')
def upload_webapp(self, manifest_url, **post_kw):
self.upload.update(name=manifest_url) # Simulate JS upload.
return self.post(**post_kw)
def post_manifest(self, manifest_url):
rs = self.client.post(reverse('mkt.developers.upload_manifest'),
dict(manifest=manifest_url))
if 'json' in rs['content-type']:
rs = json.loads(rs.content)
return rs
def test_duplicate_domain(self):
waffle.models.Switch.objects.create(name='webapps-unique-by-domain',
active=True)
rs = self.upload_webapp('http://existing-app.com/my.webapp',
expect_errors=True)
eq_(rs.context['form'].errors,
{'upload':
['An app already exists on this domain; only one '
'app per domain is allowed.']})
def test_allow_duplicate_domains(self):
self.upload_webapp('http://existing-app.com/my.webapp') # No errors.
def test_duplicate_domain_from_js(self):
waffle.models.Switch.objects.create(name='webapps-unique-by-domain',
active=True)
data = self.post_manifest('http://existing-app.com/my.webapp')
eq_(data['validation']['errors'], 1)
eq_(data['validation']['messages'][0]['message'],
'An app already exists on this domain; '
'only one app per domain is allowed.')
def test_allow_duplicate_domains_from_js(self):
rs = self.post_manifest('http://existing-app.com/my.webapp')
eq_(rs.status_code, 302)
2012-02-21 13:13:03 +04:00
class TestDetails(TestSubmit):
fixtures = ['base/apps', 'base/users', 'webapps/337141-steamcube']
2012-02-21 13:13:03 +04:00
def setUp(self):
super(TestDetails, self).setUp()
self.webapp = self.get_webapp()
self.webapp.update(status=amo.STATUS_NULL)
2012-02-21 13:13:03 +04:00
self.url = reverse('submit.app.details', args=[self.webapp.app_slug])
def get_webapp(self):
return Webapp.objects.get(id=337141)
2012-02-24 02:36:42 +04:00
def upload_preview(self, image_file=None):
return self._upload_image(self.webapp.get_dev_url('upload_preview'),
image_file=image_file)
2012-02-24 02:36:42 +04:00
def upload_icon(self, image_file=None):
return self._upload_image(self.webapp.get_dev_url('upload_icon'),
image_file=image_file)
2012-02-24 02:36:42 +04:00
def _upload_image(self, url, image_file=None):
if not image_file:
image_file = get_image_path('non-animated.png')
with open(image_file, 'rb') as data:
rp = self.client.post(url, {'upload_image': data})
eq_(rp.status_code, 200)
return json.loads(rp.content)['upload_hash']
2012-02-21 13:13:03 +04:00
def _step(self):
#self.user.update(read_dev_agreement=datetime.datetime.now())
self.user.update(read_dev_agreement=True)
2012-02-21 13:13:03 +04:00
self.cl = AppSubmissionChecklist.objects.create(addon=self.webapp,
terms=True, manifest=True)
# Associate app with user.
2012-02-21 13:13:03 +04:00
AddonUser.objects.create(addon=self.webapp, user=self.user)
# Associate device type with app.
self.dtype = DeviceType.objects.create(name='fligphone')
AddonDeviceType.objects.create(addon=self.webapp,
device_type=self.dtype)
# Associate category with app.
self.cat1 = Category.objects.create(type=amo.ADDON_WEBAPP, name='Fun')
AddonCategory.objects.create(addon=self.webapp, category=self.cat1)
# Create initial formset for categories.
ctx = self.client.get(self.url).context['form_cats']
self.cat_initial = amo.tests.initial(ctx.initial_forms[0])
2012-02-21 13:13:03 +04:00
def test_anonymous(self):
self._test_anonymous()
def test_resume_step(self):
self._step()
payments_url = reverse('submit.app.payments',
args=[self.webapp.app_slug])
r = self.client.get(payments_url, follow=True)
self.assertRedirects(r, reverse('submit.app.details',
args=[self.webapp.app_slug]))
2012-02-21 13:13:03 +04:00
def test_resume_later(self):
self._step()
self.webapp.appsubmissionchecklist.update(details=True, payments=True)
self.webapp.update(status=amo.STATUS_NULL, paypal_id='',
premium_type=amo.ADDON_PREMIUM)
res = self.client.get(reverse('submit.app.resume',
args=[self.webapp.app_slug]))
self.assertRedirects(res, self.webapp.get_dev_url('paypal_setup'))
2012-02-21 13:13:03 +04:00
def test_not_owner(self):
self._step()
assert self.client.login(username='clouserw@gmail.com',
password='password')
eq_(self.client.get(self.url).status_code, 403)
def test_page(self):
self._step()
r = self.client.get(self.url)
eq_(r.status_code, 200)
eq_(pq(r.content)('#submit-details').length, 1)
def test_progress_display(self):
self._step()
self._test_progress_display(['terms', 'manifest'], 'details')
2012-02-23 04:13:31 +04:00
def new_preview_formset(self, *args, **kw):
ctx = self.client.get(self.url).context
blank = initial(ctx['form_previews'].forms[-1])
blank.update(**kw)
return blank
def preview_formset(self, *args, **kw):
kw.setdefault('initial_count', 0)
kw.setdefault('prefix', 'files')
fs = formset(*[a for a in args] + [self.new_preview_formset()], **kw)
return dict([(k, '' if v is None else v) for k, v in fs.items()])
def get_dict(self, **kw):
data = {
'name': 'Test name',
'slug': 'testname',
'summary': 'Hello!',
'description': 'desc',
'privacy_policy': 'XXX <script>alert("xss")</script>',
'homepage': 'http://www.goodreads.com/user/show/7595895-krupa',
'support_url': 'http://www.goodreads.com/user_challenges/351558',
'support_email': 'krupa+to+the+rescue@goodreads.com',
'device_types': [self.dtype.id],
}
2012-02-23 04:13:31 +04:00
# Add the required screenshot.
data.update(self.preview_formset({
'upload_hash': '<hash>',
'position': 0
}))
data.update(**kw)
# Build formset for categories.
data.update(amo.tests.formset(self.cat_initial, initial_count=1))
# Remove fields without values.
data = dict((k, v) for k, v in data.iteritems() if v is not None)
return data
def check_dict(self, data=None, expected=None):
if data is None:
data = self.get_dict()
addon = self.get_webapp()
# Build a dictionary of expected results.
expected = {
'name': 'Test name',
'app_slug': 'testname',
'summary': 'Hello!',
'description': 'desc',
'privacy_policy': 'XXX &lt;script&gt;alert("xss")&lt;/script&gt;',
}
expected.update(expected)
for field, expected in expected.iteritems():
got = unicode(getattr(addon, field))
eq_(got, expected,
'Expected %r for %r. Got %r.' % (expected, field, got))
eq_(list(addon.device_types), [self.dtype])
def test_success(self):
self._step()
2012-02-23 04:13:31 +04:00
data = self.get_dict()
# Post and be redirected.
2012-02-23 04:13:31 +04:00
r = self.client.post(self.url, data)
self.assertNoFormErrors(r)
# TODO: Assert redirects when we go to next step.
2012-02-23 04:13:31 +04:00
self.check_dict(data=data)
def test_no_video_types(self):
self._step()
res = self.client.get(self.url)
doc = pq(res.content)
eq_(doc('#screenshot_upload').attr('data-allowed-types'),
'image/jpeg|image/png')
eq_(doc('#id_icon_upload').attr('data-allowed-types'),
'image/jpeg|image/png')
def test_video_types(self):
waffle.models.Switch.objects.create(name='video-upload', active=True)
self._step()
res = self.client.get(self.url)
doc = pq(res.content)
eq_(doc('#screenshot_upload').attr('data-allowed-types'),
'image/jpeg|image/png|video/webm')
def test_screenshot(self):
self._step()
im_hash = self.upload_preview()
data = self.get_dict()
data.update(self.preview_formset({
'upload_hash': im_hash,
'position': 0
}))
rp = self.client.post(self.url, data)
eq_(rp.status_code, 302)
ad = Addon.objects.get(pk=self.webapp.pk)
eq_(ad.previews.all().count(), 1)
2012-02-24 02:36:42 +04:00
def test_icon(self):
self._step()
im_hash = self.upload_icon()
data = self.get_dict()
data['icon_upload_hash'] = im_hash
data['icon_type'] = 'image/png'
rp = self.client.post(self.url, data)
eq_(rp.status_code, 302)
ad = self.get_webapp()
eq_(ad.icon_type, 'image/png')
for size in amo.ADDON_ICON_SIZES:
fn = '%s-%s.png' % (ad.id, size)
assert os.path.exists(os.path.join(ad.get_icon_dir(), fn)), (
'Expected %s in %s' % (fn, os.listdir(ad.get_icon_dir())))
def _setup_other_webapp(self):
self._step()
# Generate another webapp to test name uniqueness.
app = amo.tests.addon_factory(type=amo.ADDON_WEBAPP, name='Cool App')
eq_(ReverseNameLookup(webapp=True).get(app.name), app.id)
def test_name_unique(self):
self._setup_other_webapp()
r = self.client.post(self.url, self.get_dict(name='Cool App'))
error = 'This name is already in use. Please choose another.'
self.assertFormError(r, 'form_basic', 'name', error)
def test_name_unique_strip(self):
# Make sure we can't sneak in a name by adding a space or two.
self._setup_other_webapp()
r = self.client.post(self.url, self.get_dict(name=' Cool App '))
error = 'This name is already in use. Please choose another.'
self.assertFormError(r, 'form_basic', 'name', error)
def test_name_unique_case(self):
# Make sure unique names aren't case sensitive.
self._setup_other_webapp()
r = self.client.post(self.url, self.get_dict(name='cool app'))
error = 'This name is already in use. Please choose another.'
self.assertFormError(r, 'form_basic', 'name', error)
def test_name_required(self):
self._step()
r = self.client.post(self.url, self.get_dict(name=''))
eq_(r.status_code, 200)
self.assertFormError(r, 'form_basic', 'name',
'This field is required.')
2012-02-23 04:13:31 +04:00
def test_screenshot_required(self):
self._step()
data = self.get_dict()
for k in data:
if k.startswith('files') and k.endswith('upload_hash'):
data[k] = ''
rp = self.client.post(self.url, data)
eq_(rp.context['form_previews'].non_form_errors(),
['You must upload at least one screenshot.'])
def test_screenshot_or_video_required(self):
waffle.models.Switch.objects.create(name='video-upload', active=True)
self._step()
data = self.get_dict()
for k in data:
if k.startswith('files') and k.endswith('upload_hash'):
data[k] = ''
rp = self.client.post(self.url, data)
eq_(rp.context['form_previews'].non_form_errors(),
['You must upload at least one screenshot or video.'])
2012-02-23 04:13:31 +04:00
def test_unsaved_screenshot(self):
self._step()
# If there are form errors we should still pass the previews URIs.
preview_type = 'video/webm'
preview_uri = 'moz-filedata:p00p'
data = self.preview_formset({
'position': 1,
'upload_hash': '<hash_one>',
'unsaved_image_type': preview_type,
'unsaved_image_data': preview_uri
})
r = self.client.post(self.url, data)
eq_(r.status_code, 200)
form = pq(r.content)('form')
eq_(form.find('input[name=files-0-unsaved_image_type]').val(),
preview_type)
eq_(form.find('input[name=files-0-unsaved_image_data]').val(),
preview_uri)
def test_name_length(self):
self._step()
r = self.client.post(self.url, self.get_dict(name='a' * 129))
eq_(r.status_code, 200)
self.assertFormError(r, 'form_basic', 'name',
'Ensure this value has at most 128 characters (it has 129).')
def test_slug_invalid(self):
self._step()
# Submit an invalid slug.
d = self.get_dict(slug='slug!!! aksl23%%')
r = self.client.post(self.url, d)
eq_(r.status_code, 200)
self.assertFormError(r, 'form_basic', 'slug',
"Enter a valid 'slug' consisting of letters, numbers, underscores "
"or hyphens.")
def test_slug_required(self):
self._step()
r = self.client.post(self.url, self.get_dict(slug=''))
eq_(r.status_code, 200)
self.assertFormError(r, 'form_basic', 'slug',
'This field is required.')
def test_summary_required(self):
self._step()
r = self.client.post(self.url, self.get_dict(summary=''))
eq_(r.status_code, 200)
self.assertFormError(r, 'form_basic', 'summary',
'This field is required.')
def test_summary_length(self):
self._step()
r = self.client.post(self.url, self.get_dict(summary='a' * 251))
eq_(r.status_code, 200)
self.assertFormError(r, 'form_basic', 'summary',
'Ensure this value has at most 250 characters (it has 251).')
2012-02-21 22:52:24 +04:00
def test_description_optional(self):
self._step()
r = self.client.post(self.url, self.get_dict(description=None))
self.assertNoFormErrors(r)
def test_privacy_policy_required(self):
self._step()
r = self.client.post(self.url, self.get_dict(privacy_policy=None))
self.assertFormError(r, 'form_basic', 'privacy_policy',
'This field is required.')
def test_clashing_locale(self):
self.webapp.default_locale = 'de'
self.webapp.save()
self._step()
self.client.cookies['current_locale'] = 'en-us'
data = self.get_dict(name=None, name_de='Test name',
privacy_policy=None,
**{'privacy_policy_en-us': 'XXX'})
r = self.client.post(self.url, data)
self.assertNoFormErrors(r)
def test_homepage_url_optional(self):
self._step()
r = self.client.post(self.url, self.get_dict(homepage=None))
self.assertNoFormErrors(r)
def test_homepage_url_invalid(self):
self._step()
r = self.client.post(self.url, self.get_dict(homepage='xxx'))
self.assertFormError(r, 'form_basic', 'homepage', 'Enter a valid URL.')
def test_support_url_optional(self):
self._step()
r = self.client.post(self.url, self.get_dict(support_url=None))
self.assertNoFormErrors(r)
def test_support_url_invalid(self):
self._step()
r = self.client.post(self.url, self.get_dict(support_url='xxx'))
self.assertFormError(r, 'form_basic', 'support_url',
'Enter a valid URL.')
def test_support_email_required(self):
self._step()
r = self.client.post(self.url, self.get_dict(support_email=None))
self.assertFormError(r, 'form_basic', 'support_email',
'This field is required.')
def test_support_email_invalid(self):
self._step()
r = self.client.post(self.url, self.get_dict(support_email='xxx'))
self.assertFormError(r, 'form_basic', 'support_email',
'Enter a valid e-mail address.')
def test_device_types_required(self):
self._step()
r = self.client.post(self.url, self.get_dict(device_types=None))
self.assertFormError(r, 'form_devices', 'device_types',
'This field is required.')
def test_device_types_invalid(self):
self._step()
r = self.client.post(self.url, self.get_dict(device_types='999'))
self.assertFormError(r, 'form_devices', 'device_types',
'Select a valid choice. 999 is not one of the available choices.')
def test_device_types_default(self):
self._step()
r = self.client.get(self.url)
eq_(r.status_code, 200)
checkboxes = pq(r.content)('input[name=device_types]')
eq_(checkboxes.length, 1)
eq_(checkboxes.filter(':checked').length, 1,
'All device types should be checked by default.')
def test_device_types_default_on_post(self):
self._step()
r = self.client.post(self.url, self.get_dict(device_types=None))
eq_(r.status_code, 200)
checkboxes = pq(r.content)('input[name=device_types]')
eq_(checkboxes.length, 1)
eq_(checkboxes.filter(':checked').length, 0,
'POSTed values should not get replaced by the defaults.')
def test_categories_required(self):
self._step()
del self.cat_initial['categories']
r = self.client.post(self.url, self.get_dict())
eq_(r.context['form_cats'].errors[0]['categories'],
['This field is required.'])
def test_categories_max(self):
self._step()
eq_(amo.MAX_CATEGORIES, 2)
cat2 = Category.objects.create(type=amo.ADDON_WEBAPP, name='bling')
cat3 = Category.objects.create(type=amo.ADDON_WEBAPP, name='blang')
self.cat_initial['categories'] = [self.cat1.id, cat2.id, cat3.id]
r = self.client.post(self.url, self.get_dict())
eq_(r.context['form_cats'].errors[0]['categories'],
['You can have only 2 categories.'])
def _post_cats(self, cats):
self.cat_initial['categories'] = [c.id for c in cats]
self.client.post(self.url, self.get_dict())
eq_(sorted(self.get_webapp().categories.values_list('id', flat=True)),
sorted(c.id for c in cats))
def test_categories_add(self):
self._step()
cat2 = Category.objects.create(type=amo.ADDON_WEBAPP, name='bling')
self._post_cats([self.cat1, cat2])
def test_categories_add_and_remove(self):
self._step()
cat2 = Category.objects.create(type=amo.ADDON_WEBAPP, name='bling')
self._post_cats([cat2])
def test_categories_remove(self):
# Add another category here so it gets added to the initial formset.
cat2 = Category.objects.create(type=amo.ADDON_WEBAPP, name='bling')
AddonCategory.objects.create(addon=self.webapp, category=cat2)
self._step()
# `cat2` should get removed.
self._post_cats([self.cat1])
2012-02-21 22:52:24 +04:00
class TestPayments(TestSubmit):
fixtures = ['base/users', 'webapps/337141-steamcube']
def setUp(self):
super(TestPayments, self).setUp()
self.webapp = self.get_webapp()
2012-02-24 21:54:42 +04:00
self.webapp.update(status=amo.STATUS_NULL)
self.url = self.get_url('payments')
self.price = Price.objects.create(price='1.00')
self._step()
def get_url(self, url):
return reverse('submit.app.%s' % url, args=[self.webapp.app_slug])
2012-02-21 22:52:24 +04:00
def get_webapp(self):
return Webapp.objects.get(id=337141)
def _step(self):
self.cl = AppSubmissionChecklist.objects.create(addon=self.webapp,
2012-02-21 23:38:54 +04:00
terms=True, manifest=True, details=True)
2012-02-21 22:52:24 +04:00
AddonUser.objects.create(addon=self.webapp, user=self.user)
def test_anonymous(self):
self._test_anonymous()
def test_required(self):
res = self.client.post(self.url, {'premium_type': ''})
eq_(res.status_code, 200)
self.assertFormError(res, 'form', 'premium_type',
'This field is required.')
2012-02-24 21:54:42 +04:00
def test_premium_type_not_valid(self):
2012-02-21 22:52:24 +04:00
res = self.client.post(self.url, {'premium_type': 124})
eq_(res.status_code, 200)
self.assertFormError(res, 'form', 'premium_type',
'Select a valid choice. 124 is not one of the available choices.')
2012-02-24 21:54:42 +04:00
def test_premium_type_valid(self):
2012-02-21 22:52:24 +04:00
res = self.client.post(self.url, {'premium_type': amo.ADDON_PREMIUM})
eq_(res.status_code, 302)
eq_(self.get_webapp().premium_type, amo.ADDON_PREMIUM)
2012-02-21 23:38:54 +04:00
def _test_valid(self, expected_status):
res = self.client.post(self.get_url('payments'),
{'premium_type': amo.ADDON_FREE})
eq_(res.status_code, 302)
self.assertRedirects(res, self.get_url('done'))
eq_(self.get_webapp().status, expected_status)
def test_valid_pending(self):
res = self.client.post(self.get_url('payments'),
{'premium_type': amo.ADDON_FREE})
eq_(res.status_code, 302)
self.assertRedirects(res, self.get_url('done'))
eq_(self.get_webapp().status, amo.WEBAPPS_UNREVIEWED_STATUS)
def test_premium(self):
for type_ in [amo.ADDON_PREMIUM, amo.ADDON_PREMIUM_INAPP]:
res = self.client.post(self.get_url('payments'),
{'premium_type': type_})
eq_(res.status_code, 302)
self.assertRedirects(res, self.get_url('payments.upsell'))
def test_free_inapp(self):
res = self.client.post(self.get_url('payments'),
{'premium_type': amo.ADDON_FREE_INAPP})
eq_(res.status_code, 302)
self.assertRedirects(res, self.get_url('payments.paypal'))
def test_premium_other(self):
res = self.client.post(self.get_url('payments'),
{'premium_type': amo.ADDON_PREMIUM_OTHER})
eq_(res.status_code, 302)
self.assertRedirects(res, self.get_url('done'))
def test_price(self):
self.webapp.update(premium_type=amo.ADDON_PREMIUM)
res = self.client.post(self.get_url('payments.upsell'),
{'price': self.price.pk})
eq_(res.status_code, 302)
eq_(self.get_webapp().premium.price.pk, self.price.pk)
self.assertRedirects(res, self.get_url('payments.paypal'))
def _make_upsell(self):
free = Addon.objects.create(type=amo.ADDON_WEBAPP)
free.update(status=amo.STATUS_PUBLIC)
AddonUser.objects.create(addon=free, user=self.user)
return free
def test_immediate(self):
self.webapp.update(premium_type=amo.ADDON_PREMIUM)
res = self.client.post(self.get_url('payments.upsell'),
{'price': self.price.pk,
'make_public': 0})
eq_(res.status_code, 302)
eq_(self.get_webapp().make_public, amo.PUBLIC_IMMEDIATELY)
def test_wait(self):
self.webapp.update(premium_type=amo.ADDON_PREMIUM)
res = self.client.post(self.get_url('payments.upsell'),
{'price': self.price.pk,
'make_public': 1})
eq_(res.status_code, 302)
eq_(self.get_webapp().make_public, amo.PUBLIC_WAIT)
def test_upsell_states(self):
free = self._make_upsell()
free.update(status=amo.STATUS_NULL)
res = self.client.get(self.get_url('payments.upsell'))
eq_(len(res.context['form'].fields['free'].choices), 0)
def test_upsell_states_inapp(self):
free = self._make_upsell()
free.update(premium_type=amo.ADDON_FREE_INAPP)
res = self.client.get(self.get_url('payments.upsell'))
eq_(len(res.context['form'].fields['free'].choices), 1)
def test_upsell(self):
free = self._make_upsell()
self.webapp.update(premium_type=amo.ADDON_PREMIUM)
res = self.client.post(self.get_url('payments.upsell'),
{'price': self.price.pk,
'do_upsell': 1,
'free': free.pk,
'text': 'some upsell',
})
eq_(self.get_webapp().premium.price.pk, self.price.pk)
eq_(self.get_webapp().upsold.free.pk, free.pk)
eq_(self.get_webapp().upsold.premium.pk, self.get_webapp().pk)
eq_(res.status_code, 302)
self.assertRedirects(res, self.get_url('payments.paypal'))
2012-02-23 04:47:42 +04:00
def test_no_upsell(self):
self.webapp.update(premium_type=amo.ADDON_PREMIUM)
res = self.client.get(self.get_url('payments.upsell'),
{'price': self.price.pk})
eq_(res.status_code, 200)
eq_(len(pq(res.content)('div.brform')), 3)
2012-02-23 04:47:42 +04:00
def test_upsell_missing(self):
free = Addon.objects.create(type=amo.ADDON_WEBAPP)
AddonUser.objects.create(addon=free, user=self.user)
self.webapp.update(premium_type=amo.ADDON_PREMIUM)
res = self.client.post(self.get_url('payments.upsell'),
{'price': self.price.pk,
'do_upsell': 1,
})
eq_(res.status_code, 200)
def test_bad_upsell(self):
2012-02-23 00:46:39 +04:00
self.webapp.update(premium_type=amo.ADDON_PREMIUM)
2012-02-23 04:13:31 +04:00
res = self.client.post(self.get_url('payments.upsell'), {'price': ''})
2012-02-23 00:46:39 +04:00
eq_(res.status_code, 200)
self.assertFormError(res, 'form', 'price', 'This field is required.')
def test_paypal(self):
self.webapp.update(premium_type=amo.ADDON_PREMIUM)
res = self.client.post(self.get_url('payments.paypal'),
2012-02-23 00:46:39 +04:00
{'business_account': 'yes',
'email': 'foo@bar.com'})
eq_(self.get_webapp().paypal_id, 'foo@bar.com')
eq_(res.status_code, 302)
self.assertRedirects(res, self.get_url('payments.bounce'))
@mock.patch('mkt.submit.views.client')
@mock.patch('mkt.submit.views.waffle.flag_is_active')
def test_paypal_solitude(self, flag_is_active, client):
self.webapp.update(premium_type=amo.ADDON_PREMIUM)
res = self.client.post(self.get_url('payments.paypal'),
{'business_account': 'yes',
'email': 'foo@bar.com'})
eq_(client.create_seller_paypal.call_args[0][0], self.webapp)
eq_(client.patch_seller_paypal.call_args[1]['data']['paypal_id'],
'foo@bar.com')
self.assertRedirects(res, self.get_url('payments.bounce'))
2012-02-23 10:11:51 +04:00
def test_no_paypal(self):
self.webapp.update(premium_type=amo.ADDON_PREMIUM)
res = self.client.post(self.get_url('payments.paypal'),
{'business_account': 'no'})
eq_(res.status_code, 302)
eq_(res._headers['location'][1], settings.PAYPAL_CGI_URL)
def test_later_paypal(self):
self.webapp.update(premium_type=amo.ADDON_PREMIUM)
res = self.client.post(self.get_url('payments.paypal'),
{'business_account': 'later'})
eq_(res.status_code, 302)
self.assertRedirects(res, self.get_url('done'))
def get_acquire_url(self):
url = self.webapp.get_dev_url('acquire_refund_permission')
return urlparams(url, dest='submission', request_token='foo',
verification_code='foo')
@mock.patch('paypal.get_permissions_token')
@mock.patch('paypal.get_personal_data')
def test_bounce_result_works(self, get_personal_data,
get_permissions_token):
2012-04-03 01:18:37 +04:00
self.webapp.update(premium_type=amo.ADDON_PREMIUM,
paypal_id='a@a.com')
get_permissions_token.return_value = 'foo'
2012-04-03 01:18:37 +04:00
get_personal_data.return_value = {'email': 'a@a.com'}
res = self.client.get(self.get_acquire_url())
self.assertRedirects(res, self.get_url('payments.confirm'))
2012-04-03 01:18:37 +04:00
@mock.patch('paypal.get_permissions_token')
@mock.patch('paypal.get_personal_data')
2012-04-04 03:08:07 +04:00
def test_bounce_result_fails_email(self, get_personal_data,
2012-04-03 01:18:37 +04:00
get_permissions_token):
self.webapp.update(premium_type=amo.ADDON_PREMIUM,
paypal_id='b@b.com')
get_permissions_token.return_value = 'foo'
get_personal_data.return_value = {'email': 'a@a.com'}
res = self.client.get(self.get_acquire_url())
2012-04-04 03:08:07 +04:00
self.assertRedirects(res, self.get_url('payments.paypal'))
2012-04-03 01:18:37 +04:00
@mock.patch('paypal.get_permissions_token')
2012-04-04 03:08:07 +04:00
def test_bounce_result_fails_paypal_error(self, get_permissions_token):
self.webapp.update(premium_type=amo.ADDON_PREMIUM)
get_permissions_token.side_effect = paypal.PaypalError
res = self.client.get(self.get_acquire_url())
eq_(res.status_code, 500)
self.assertTemplateUsed(res, 'site/500_paypal.html')
doc = pq(res.content)
eq_(doc('div.prose form a').attr('href'),
self.get_url('payments.bounce'))
eq_(doc('div.prose form').attr('action'),
self.get_url('payments.paypal'))
2012-02-21 23:38:54 +04:00
class TestDone(TestSubmit):
fixtures = ['base/users', 'webapps/337141-steamcube']
def setUp(self):
super(TestDone, self).setUp()
self.webapp = self.get_webapp()
self.url = reverse('submit.app.done', args=[self.webapp.app_slug])
def get_webapp(self):
return Webapp.objects.get(id=337141)
def _step(self):
self.cl = AppSubmissionChecklist.objects.create(addon=self.webapp,
terms=True, manifest=True, details=True, payments=True)
AddonUser.objects.create(addon=self.webapp, user=self.user)
def test_anonymous(self):
self._test_anonymous()
def test_done(self):
self._step()
res = self.client.get(self.url)
eq_(res.status_code, 200)