2012-02-21 01:59:14 +04:00
|
|
|
import json
|
|
|
|
import os
|
|
|
|
|
|
|
|
from django.conf import settings
|
|
|
|
|
|
|
|
import mock
|
2012-02-14 12:36:10 +04:00
|
|
|
from nose.tools import eq_
|
2012-02-22 22:51:00 +04:00
|
|
|
from nose import SkipTest
|
2012-02-14 12:36:10 +04:00
|
|
|
from pyquery import PyQuery as pq
|
2012-02-21 01:59:14 +04:00
|
|
|
import waffle
|
2012-02-14 12:36:10 +04:00
|
|
|
|
|
|
|
import amo
|
|
|
|
import amo.tests
|
2012-02-23 04:13:31 +04:00
|
|
|
from amo.tests import formset, initial
|
2012-02-14 12:36:10 +04:00
|
|
|
from amo.urlresolvers import reverse
|
2012-02-22 12:56:36 +04:00
|
|
|
from addons.models import (Addon, AddonCategory, AddonDeviceType, AddonUser,
|
|
|
|
Category, DeviceType)
|
2012-02-21 15:49:37 +04:00
|
|
|
from addons.utils import ReverseNameLookup
|
2012-02-21 01:59:14 +04:00
|
|
|
from files.tests.test_models import UploadTest as BaseUploadTest
|
2012-02-22 22:51:00 +04:00
|
|
|
from market.models import Price
|
2012-02-20 14:21:06 +04:00
|
|
|
import mkt
|
2012-02-21 13:13:03 +04:00
|
|
|
from mkt.submit.models import AppSubmissionChecklist
|
2012-02-21 01:59:14 +04:00
|
|
|
from translations.models import Translation
|
2012-02-14 12:36:10 +04:00
|
|
|
from users.models import UserProfile
|
2012-02-21 01:59:14 +04:00
|
|
|
from webapps.models import Webapp
|
2012-02-14 12:36:10 +04:00
|
|
|
|
|
|
|
|
2012-02-20 14:21:06 +04:00
|
|
|
class TestSubmit(amo.tests.TestCase):
|
2012-02-14 12:36:10 +04:00
|
|
|
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')
|
|
|
|
|
2012-02-20 14:21:06 +04:00
|
|
|
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 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.url = reverse('submit.app.terms')
|
|
|
|
|
2012-02-14 12:36:10 +04:00
|
|
|
def test_anonymous(self):
|
|
|
|
self.client.logout()
|
|
|
|
r = self.client.get(self.url, follow=True)
|
|
|
|
self.assertLoginRedirects(r, self.url)
|
|
|
|
|
2012-02-20 14:21:06 +04:00
|
|
|
def test_jump_to_step(self):
|
|
|
|
r = self.client.get(reverse('submit.app'), follow=True)
|
2012-02-14 12:36:10 +04:00
|
|
|
self.assertRedirects(r, self.url)
|
|
|
|
|
2012-02-20 14:21:06 +04:00
|
|
|
def test_page(self):
|
2012-02-14 12:36:10 +04:00
|
|
|
r = self.client.get(self.url)
|
|
|
|
eq_(r.status_code, 200)
|
2012-02-20 14:21:06 +04:00
|
|
|
eq_(pq(r.content)('#submit-terms').length, 1)
|
|
|
|
|
|
|
|
def test_progress_display(self):
|
|
|
|
self._test_progress_display([], 'terms')
|
2012-02-14 12:36:10 +04:00
|
|
|
|
|
|
|
def test_agree(self):
|
|
|
|
r = self.client.post(self.url, {'read_dev_agreement': True})
|
2012-02-20 14:21:06 +04:00
|
|
|
self.assertRedirects(r, reverse('submit.app.manifest'))
|
2012-02-14 12:36:10 +04:00
|
|
|
eq_(self.get_user().read_dev_agreement, True)
|
|
|
|
|
|
|
|
def test_disagree(self):
|
|
|
|
r = self.client.post(self.url)
|
|
|
|
eq_(r.status_code, 200)
|
|
|
|
eq_(self.user.read_dev_agreement, False)
|
2012-02-20 14:21:06 +04:00
|
|
|
|
|
|
|
|
|
|
|
class TestManifest(TestSubmit):
|
|
|
|
fixtures = ['base/users']
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
super(TestManifest, self).setUp()
|
|
|
|
self.url = reverse('submit.app.manifest')
|
|
|
|
|
|
|
|
def _step(self):
|
|
|
|
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')
|
2012-02-21 01:59:14 +04:00
|
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
waffle.models.Flag.objects.create(name='accept-webapps', everyone=True)
|
|
|
|
self.manifest = os.path.join(settings.ROOT, 'mkt', 'submit', 'tests',
|
|
|
|
'webapps', 'mozball.webapp')
|
|
|
|
self.upload = self.get_upload(abspath=self.manifest)
|
|
|
|
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)
|
2012-02-21 01:59:14 +04:00
|
|
|
self.post()
|
2012-02-21 03:43:51 +04:00
|
|
|
return Addon.objects.get()
|
2012-02-21 01:59:14 +04:00
|
|
|
|
|
|
|
|
|
|
|
class TestCreateWebApp(BaseWebAppTest):
|
|
|
|
|
|
|
|
def test_page_title(self):
|
|
|
|
eq_(pq(self.client.get(self.url).content)('title').text(),
|
|
|
|
'App Manifest | Developer Hub | Mozilla Marketplace')
|
|
|
|
|
|
|
|
def test_post_app_redirect(self):
|
|
|
|
r = self.post()
|
|
|
|
webapp = Webapp.objects.get()
|
|
|
|
self.assertRedirects(r,
|
|
|
|
reverse('submit.app.details', args=[webapp.app_slug]))
|
|
|
|
|
2012-02-21 03:43:51 +04:00
|
|
|
def test_app_from_uploaded_manifest(self):
|
2012-02-21 01:59:14 +04:00
|
|
|
addon = self.post_addon()
|
|
|
|
eq_(addon.type, amo.ADDON_WEBAPP)
|
|
|
|
eq_(addon.guid, None)
|
|
|
|
eq_(unicode(addon.name), 'MozillaBall')
|
|
|
|
eq_(addon.slug, 'app-%s' % addon.id)
|
|
|
|
eq_(addon.app_slug, '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_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='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
|
|
|
|
|
|
|
|
@mock.patch.object(settings, 'WEBAPPS_UNIQUE_BY_DOMAIN', True)
|
|
|
|
def test_duplicate_domain(self):
|
|
|
|
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.']})
|
|
|
|
|
|
|
|
@mock.patch.object(settings, 'WEBAPPS_UNIQUE_BY_DOMAIN', False)
|
|
|
|
def test_allow_duplicate_domains(self):
|
|
|
|
self.upload_webapp('http://existing-app.com/my.webapp') # No errors.
|
|
|
|
|
|
|
|
@mock.patch.object(settings, 'WEBAPPS_UNIQUE_BY_DOMAIN', True)
|
|
|
|
def test_duplicate_domain_from_js(self):
|
|
|
|
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.')
|
|
|
|
|
|
|
|
@mock.patch.object(settings, 'WEBAPPS_UNIQUE_BY_DOMAIN', False)
|
|
|
|
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):
|
2012-02-22 12:56:36 +04:00
|
|
|
fixtures = ['base/apps', 'base/users', 'webapps/337141-steamcube']
|
2012-02-21 13:13:03 +04:00
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
super(TestDetails, self).setUp()
|
2012-02-21 15:49:37 +04:00
|
|
|
self.webapp = self.get_webapp()
|
2012-02-21 13:13:03 +04:00
|
|
|
self.url = reverse('submit.app.details', args=[self.webapp.app_slug])
|
2012-02-22 12:56:36 +04:00
|
|
|
waffle.models.Flag.objects.create(name='accept-webapps', everyone=True)
|
2012-02-21 13:13:03 +04:00
|
|
|
|
2012-02-21 15:49:37 +04:00
|
|
|
def get_webapp(self):
|
|
|
|
return Webapp.objects.get(id=337141)
|
|
|
|
|
2012-02-21 13:13:03 +04:00
|
|
|
def _step(self):
|
|
|
|
self.user.update(read_dev_agreement=True)
|
|
|
|
self.cl = AppSubmissionChecklist.objects.create(addon=self.webapp,
|
|
|
|
terms=True, manifest=True)
|
2012-02-22 11:04:55 +04:00
|
|
|
|
|
|
|
# Associate app with user.
|
2012-02-21 13:13:03 +04:00
|
|
|
AddonUser.objects.create(addon=self.webapp, user=self.user)
|
|
|
|
|
2012-02-22 11:04:55 +04:00
|
|
|
# Associate device type with app.
|
|
|
|
self.dtype = DeviceType.objects.create(name='fligphone')
|
|
|
|
AddonDeviceType.objects.create(addon=self.webapp,
|
|
|
|
device_type=self.dtype)
|
|
|
|
|
2012-02-22 12:56:36 +04:00
|
|
|
# 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)
|
2012-02-22 03:55:57 +04:00
|
|
|
self.assertRedirects(r, reverse('submit.app.details',
|
|
|
|
args=[self.webapp.app_slug]))
|
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-21 15:49:37 +04:00
|
|
|
|
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()])
|
|
|
|
|
2012-02-21 15:49:37 +04:00
|
|
|
def get_dict(self, **kw):
|
2012-02-22 11:04:55 +04:00
|
|
|
data = {
|
2012-02-22 07:43:15 +04:00
|
|
|
'name': 'Test name',
|
|
|
|
'slug': 'testname',
|
|
|
|
'summary': 'Hello!',
|
|
|
|
'description': 'desc',
|
2012-02-22 11:04:55 +04:00
|
|
|
'privacy_policy': 'XXX <script>alert("xss")</script>',
|
|
|
|
'device_types': [self.dtype.id],
|
2012-02-22 07:43:15 +04:00
|
|
|
}
|
2012-02-23 04:13:31 +04:00
|
|
|
# Add the required screenshot.
|
|
|
|
data.update(self.preview_formset({
|
|
|
|
'upload_hash': '<hash>',
|
|
|
|
'position': 0
|
|
|
|
}))
|
2012-02-22 11:04:55 +04:00
|
|
|
data.update(**kw)
|
2012-02-22 12:56:36 +04:00
|
|
|
# Build formset for categories.
|
|
|
|
data.update(amo.tests.formset(self.cat_initial, initial_count=1))
|
2012-02-22 11:04:55 +04:00
|
|
|
# Remove fields without values.
|
|
|
|
data = dict((k, v) for k, v in data.iteritems() if v is not None)
|
|
|
|
return data
|
2012-02-22 07:43:15 +04:00
|
|
|
|
2012-02-22 11:04:55 +04:00
|
|
|
def check_dict(self, data=None, expected=None):
|
2012-02-22 07:43:15 +04:00
|
|
|
if data is None:
|
|
|
|
data = self.get_dict()
|
|
|
|
addon = self.get_webapp()
|
|
|
|
|
|
|
|
# Build a dictionary of expected results.
|
2012-02-22 11:04:55 +04:00
|
|
|
expected = {
|
|
|
|
'name': 'Test name',
|
|
|
|
'app_slug': 'testname',
|
|
|
|
'summary': 'Hello!',
|
|
|
|
'description': 'desc',
|
|
|
|
'privacy_policy': 'XXX <script>alert("xss")</script>',
|
|
|
|
}
|
|
|
|
expected.update(expected)
|
|
|
|
|
|
|
|
for field, expected in expected.iteritems():
|
2012-02-22 07:43:15 +04:00
|
|
|
got = unicode(getattr(addon, field))
|
|
|
|
eq_(got, expected,
|
|
|
|
'Expected %r for %r. Got %r.' % (expected, field, got))
|
2012-02-22 11:04:55 +04:00
|
|
|
eq_(list(addon.device_types), [self.dtype])
|
2012-02-21 15:49:37 +04:00
|
|
|
|
2012-02-22 02:45:32 +04:00
|
|
|
def test_success(self):
|
2012-02-21 15:49:37 +04:00
|
|
|
self._step()
|
2012-02-23 04:13:31 +04:00
|
|
|
data = self.get_dict()
|
2012-02-21 15:49:37 +04:00
|
|
|
# Post and be redirected.
|
2012-02-23 04:13:31 +04:00
|
|
|
r = self.client.post(self.url, data)
|
2012-02-22 07:43:15 +04:00
|
|
|
self.assertNoFormErrors(r)
|
2012-02-21 15:49:37 +04:00
|
|
|
# TODO: Assert redirects when we go to next step.
|
2012-02-23 04:13:31 +04:00
|
|
|
self.check_dict(data=data)
|
2012-02-21 15:49:37 +04:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2012-02-22 02:45:32 +04:00
|
|
|
def test_name_unique(self):
|
2012-02-21 15:49:37 +04:00
|
|
|
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)
|
|
|
|
|
2012-02-22 02:45:32 +04:00
|
|
|
def test_name_unique_strip(self):
|
2012-02-21 15:49:37 +04:00
|
|
|
# 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)
|
|
|
|
|
2012-02-22 02:45:32 +04:00
|
|
|
def test_name_unique_case(self):
|
2012-02-21 15:49:37 +04:00
|
|
|
# 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)
|
|
|
|
|
2012-02-22 02:45:32 +04:00
|
|
|
def test_name_required(self):
|
2012-02-21 15:49:37 +04:00
|
|
|
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 screen shot.'])
|
|
|
|
|
2012-02-22 02:45:32 +04:00
|
|
|
def test_name_length(self):
|
2012-02-21 15:49:37 +04:00
|
|
|
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).')
|
|
|
|
|
2012-02-22 02:45:32 +04:00
|
|
|
def test_slug_invalid(self):
|
2012-02-21 15:49:37 +04:00
|
|
|
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.")
|
|
|
|
|
2012-02-22 02:45:32 +04:00
|
|
|
def test_slug_required(self):
|
2012-02-21 15:49:37 +04:00
|
|
|
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.')
|
|
|
|
|
2012-02-22 02:45:32 +04:00
|
|
|
def test_summary_required(self):
|
2012-02-21 15:49:37 +04:00
|
|
|
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.')
|
|
|
|
|
2012-02-22 02:45:32 +04:00
|
|
|
def test_summary_length(self):
|
2012-02-21 15:49:37 +04:00
|
|
|
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
|
|
|
|
2012-02-22 02:45:32 +04:00
|
|
|
def test_description_optional(self):
|
|
|
|
self._step()
|
2012-02-22 11:04:55 +04:00
|
|
|
r = self.client.post(self.url, self.get_dict(description=None))
|
2012-02-22 02:45:32 +04:00
|
|
|
self.assertNoFormErrors(r)
|
|
|
|
|
2012-02-22 11:04:55 +04:00
|
|
|
def test_privacy_policy_required(self):
|
2012-02-22 07:43:15 +04:00
|
|
|
self._step()
|
2012-02-22 11:04:55 +04:00
|
|
|
r = self.client.post(self.url, self.get_dict(privacy_policy=None))
|
2012-02-22 07:43:15 +04:00
|
|
|
self.assertFormError(r, 'form_basic', 'privacy_policy',
|
|
|
|
'This field is required.')
|
|
|
|
|
2012-02-22 11:04:55 +04:00
|
|
|
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.')
|
|
|
|
|
2012-02-22 12:56:36 +04:00
|
|
|
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()
|
|
|
|
self.url = reverse('submit.app.payments', args=[self.webapp.app_slug])
|
|
|
|
|
|
|
|
def get_webapp(self):
|
|
|
|
return Webapp.objects.get(id=337141)
|
|
|
|
|
|
|
|
def _step(self):
|
|
|
|
self.user.update(read_dev_agreement=True)
|
|
|
|
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):
|
|
|
|
self._step()
|
|
|
|
res = self.client.post(self.url, {'premium_type': ''})
|
|
|
|
eq_(res.status_code, 200)
|
|
|
|
self.assertFormError(res, 'form', 'premium_type',
|
|
|
|
'This field is required.')
|
|
|
|
|
|
|
|
def test_not_valid(self):
|
|
|
|
self._step()
|
|
|
|
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.')
|
|
|
|
|
|
|
|
def test_valid(self):
|
|
|
|
self._step()
|
|
|
|
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
|
|
|
|
|
|
|
|
2012-02-22 22:51:00 +04:00
|
|
|
class TestPaymentsAdvanced(TestSubmit):
|
|
|
|
fixtures = ['base/users', 'webapps/337141-steamcube']
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
super(TestPaymentsAdvanced, self).setUp()
|
|
|
|
AppSubmissionChecklist.objects.all().delete() # TODO fix this.
|
|
|
|
self.webapp = self.get_webapp()
|
|
|
|
self.url = self.get_url('payments')
|
|
|
|
self.price = Price.objects.create(price='1.00')
|
|
|
|
flag = (waffle.models.Flag
|
|
|
|
.objects.create(name='advanced-payments-submission'))
|
|
|
|
flag.everyone = True
|
|
|
|
flag.save()
|
|
|
|
self._step()
|
|
|
|
|
|
|
|
def get_url(self, url):
|
|
|
|
return reverse('submit.app.%s' % url, args=[self.webapp.app_slug])
|
|
|
|
|
|
|
|
def get_webapp(self):
|
|
|
|
return Webapp.objects.get(id=337141)
|
|
|
|
|
|
|
|
def _step(self):
|
|
|
|
self.user.update(read_dev_agreement=True)
|
|
|
|
self.cl = AppSubmissionChecklist.objects.create(addon=self.webapp,
|
|
|
|
terms=True, manifest=True, details=True)
|
|
|
|
AddonUser.objects.create(addon=self.webapp, user=self.user)
|
|
|
|
|
|
|
|
def test_anonymous(self):
|
|
|
|
self._test_anonymous()
|
|
|
|
|
|
|
|
def test_valid(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'))
|
|
|
|
|
|
|
|
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'))
|
|
|
|
|
2012-02-23 03:43:31 +04:00
|
|
|
def test_price(self):
|
2012-02-22 22:51:00 +04:00
|
|
|
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)
|
2012-02-23 03:43:31 +04:00
|
|
|
eq_(self.get_webapp().premium.price.pk, self.price.pk)
|
2012-02-22 22:51:00 +04:00
|
|
|
self.assertRedirects(res, self.get_url('payments.paypal'))
|
|
|
|
|
2012-02-23 03:43:31 +04:00
|
|
|
def test_upsell(self):
|
|
|
|
free = Addon.objects.create(type=amo.ADDON_WEBAPP)
|
|
|
|
AddonUser.objects.create(addon=free,
|
|
|
|
user=self.webapp.authors.all()[0])
|
|
|
|
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'))
|
|
|
|
|
|
|
|
def test_upsell_missing(self):
|
|
|
|
free = Addon.objects.create(type=amo.ADDON_WEBAPP)
|
|
|
|
AddonUser.objects.create(addon=free,
|
|
|
|
user=self.webapp.authors.all()[0])
|
|
|
|
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)
|
|
|
|
|
2012-02-22 22:51:00 +04:00
|
|
|
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.')
|
2012-02-22 22:51:00 +04:00
|
|
|
|
|
|
|
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'))
|
2012-02-22 22:51:00 +04:00
|
|
|
|
|
|
|
def test_bad_paypal(self):
|
|
|
|
# some tests for when it goes wrong
|
|
|
|
raise SkipTest
|
|
|
|
|
|
|
|
def test_acquire(self):
|
|
|
|
raise SkipTest
|
|
|
|
|
|
|
|
def test_confirm(self):
|
|
|
|
raise SkipTest
|
|
|
|
# and this is where it all breaks down, need to figure out
|
|
|
|
# how to test this new flow.
|
|
|
|
|
|
|
|
|
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.user.update(read_dev_agreement=True)
|
|
|
|
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)
|