diff --git a/homeassistant/components/shopping_list.py b/homeassistant/components/shopping_list.py index 650d23fe1df..ad4680982b4 100644 --- a/homeassistant/components/shopping_list.py +++ b/homeassistant/components/shopping_list.py @@ -39,6 +39,7 @@ SERVICE_ITEM_SCHEMA = vol.Schema({ WS_TYPE_SHOPPING_LIST_ITEMS = 'shopping_list/items' WS_TYPE_SHOPPING_LIST_ADD_ITEM = 'shopping_list/items/add' +WS_TYPE_SHOPPING_LIST_UPDATE_ITEM = 'shopping_list/items/update' SCHEMA_WEBSOCKET_ITEMS = \ websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({ @@ -51,6 +52,14 @@ SCHEMA_WEBSOCKET_ADD_ITEM = \ vol.Required('name'): str }) +SCHEMA_WEBSOCKET_UPDATE_ITEM = \ + websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({ + vol.Required('type'): WS_TYPE_SHOPPING_LIST_UPDATE_ITEM, + vol.Required('item_id'): str, + vol.Optional('name'): str, + vol.Optional('complete'): bool + }) + @asyncio.coroutine def async_setup(hass, config): @@ -114,6 +123,10 @@ def async_setup(hass, config): WS_TYPE_SHOPPING_LIST_ADD_ITEM, websocket_handle_add, SCHEMA_WEBSOCKET_ADD_ITEM) + hass.components.websocket_api.async_register_command( + WS_TYPE_SHOPPING_LIST_UPDATE_ITEM, + websocket_handle_update, + SCHEMA_WEBSOCKET_UPDATE_ITEM) return True @@ -296,3 +309,21 @@ def websocket_handle_add(hass, connection, msg): hass.bus.async_fire(EVENT) connection.send_message(websocket_api.result_message( msg['id'], item)) + + +@websocket_api.async_response +async def websocket_handle_update(hass, connection, msg): + """Handle update shopping_list item.""" + msg_id = msg.pop('id') + item_id = msg.pop('item_id') + msg.pop('type') + data = msg + + try: + item = hass.data[DOMAIN].async_update(item_id, data) + hass.bus.async_fire(EVENT) + connection.send_message(websocket_api.result_message( + msg_id, item)) + except KeyError: + connection.send_message(websocket_api.error_message( + msg_id, 'item_not_found', 'Item not found')) diff --git a/tests/components/test_shopping_list.py b/tests/components/test_shopping_list.py index 44714138eb3..c2899f6b753 100644 --- a/tests/components/test_shopping_list.py +++ b/tests/components/test_shopping_list.py @@ -110,7 +110,7 @@ async def test_ws_get_items(hass, hass_ws_client): @asyncio.coroutine -def test_api_update(hass, aiohttp_client): +def test_deprecated_api_update(hass, aiohttp_client): """Test the API.""" yield from async_setup_component(hass, 'shopping_list', {}) @@ -164,6 +164,61 @@ def test_api_update(hass, aiohttp_client): } +async def test_ws_update_item(hass, hass_ws_client): + """Test update shopping_list item websocket command.""" + await async_setup_component(hass, 'shopping_list', {}) + await intent.async_handle( + hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}} + ) + await intent.async_handle( + hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'wine'}} + ) + + beer_id = hass.data['shopping_list'].items[0]['id'] + wine_id = hass.data['shopping_list'].items[1]['id'] + client = await hass_ws_client(hass) + await client.send_json({ + 'id': 5, + 'type': 'shopping_list/items/update', + 'item_id': beer_id, + 'name': 'soda' + }) + msg = await client.receive_json() + assert msg['success'] is True + data = msg['result'] + assert data == { + 'id': beer_id, + 'name': 'soda', + 'complete': False + } + await client.send_json({ + 'id': 6, + 'type': 'shopping_list/items/update', + 'item_id': wine_id, + 'complete': True + }) + msg = await client.receive_json() + assert msg['success'] is True + data = msg['result'] + assert data == { + 'id': wine_id, + 'name': 'wine', + 'complete': True + } + + beer, wine = hass.data['shopping_list'].items + assert beer == { + 'id': beer_id, + 'name': 'soda', + 'complete': False + } + assert wine == { + 'id': wine_id, + 'name': 'wine', + 'complete': True + } + + @asyncio.coroutine def test_api_update_fails(hass, aiohttp_client): """Test the API.""" @@ -190,6 +245,35 @@ def test_api_update_fails(hass, aiohttp_client): assert resp.status == 400 +async def test_ws_update_item_fail(hass, hass_ws_client): + """Test failure of update shopping_list item websocket command.""" + await async_setup_component(hass, 'shopping_list', {}) + await intent.async_handle( + hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}} + ) + client = await hass_ws_client(hass) + await client.send_json({ + 'id': 5, + 'type': 'shopping_list/items/update', + 'item_id': 'non_existing', + 'name': 'soda' + }) + msg = await client.receive_json() + assert msg['success'] is False + data = msg['error'] + assert data == { + 'code': 'item_not_found', + 'message': 'Item not found' + } + await client.send_json({ + 'id': 6, + 'type': 'shopping_list/items/update', + 'name': 123, + }) + msg = await client.receive_json() + assert msg['success'] is False + + @asyncio.coroutine def test_api_clear_completed(hass, aiohttp_client): """Test the API."""